Django之模型层(二) Q查询进阶 ORM查询优化 ORM事务 ORM常用字段类型和字段参数 多对多创建方式
目录
一、Q查询进阶操作
这里主要就是让查询数据的时候,可以使用input获取的信息,进行用户交互。
from django.db.models import Q q_obj = Q() # 1.产生q对象 q_obj.connector = 'or' # 默认多个条件的连接是and可以修改为or q_obj.children.append(('pk', 1)) # 2.添加查询条件 q_obj.children.append(('price__gt', 2000)) # 支持添加多个 res = models.Book.objects.filter(q_obj) # 查询支持直接填写q对象 print(res)
二、ORM查询优化
ORM自带的特性
1.ORM的查询默认都是惰性查询(当我们不执行打印操作的时候,ORM语句不会执行,想要看到这个现象需要打开日志功能,即在配置文件中进行配置)
2.ORM的查询自带分页处理(可以通过日志展示的代码查看,日志返回的sql代码后端会有一个limit)
only与defer
前置说明
这里需要做一些具体的说明,方便大家理解only和defer。
当我们在Django中执行ORM操作进行数据库查询的时候,其实内部的代码把所有的数据库中的记录,都封装到了ORM操作的对象中去了,因此我们可以通过点的方式或是索引等方式查询到对应的数据。
但是当遇到查询的时候需要查询不在条件中的记录时,就需要执行sql语句进行查询了。
比如我们在查询的时候,需要的结果在外键对应的表中,这时候去外键对应的表中查询数据,就需要执行sql语句进行查询,并且查询一条记录需要执行一次sql语句
而我们的only的作用是把写在括号内的参数中的字段的值封装到对象中,让后续查找的时候 不需要执行sql语句进行查询,加快执行速度。或是起到一个减少代码封装的数据量,加快运行的作用。
而defer则是和only相反,写在括号内的字段值不会被封装到对象中,别的字段反而会被封装到对象中。
- only
'''数据对象+含有指定字段对应的数据''' res = models.Book.objects.only('title', 'price') print(res) # queryset [数据对象、数据对象] for obj in res: print(obj.title) # 点击括号内填写的字段 不走SQL查询 print(obj.price) print(obj.publish_time) # 可以点击括号内没有的字段获取数据 但是会走SQL查询
案例
- defer
res = models.Book.objects.defer('title', 'price') # print(res) # queryset [数据对象、数据对象] for obj in res: # print(obj.title) # 点击括号内填写的字段 走SQL查询 # print(obj.price) print(obj.publish_time) # 点击括号内没有的字段获取数据 不走SQL查询
案例
select_related与prefetch_related
select_related括号内填写一对多、一对一字段 自动连表然后继续数据封装
prefetch_related括号内填写一对多、一对一字段 基于子查询然后封装数据
res = models.Book.objects.all() for obj in res: print(obj.publish.name) # 每次查询都需要走SQL res = models.Book.objects.select_related('authors') # 先连表后查询封装 res1 = models.Author.objects.select_related('author_detail') # 括号内不支持多对多字段 其他两个都可以 print(res1) for obj in res: print(obj.publish.name) # 不再走SQL查询 res = models.Book.objects.prefetch_related('publish') # 子查询 for obj in res: print(obj.publish.name)
select_related案例
prefetch_related案例
三、ORM事务操作
复习回忆
1.事务的四大特性(ACID)
原子性、一致性、隔离性、持久性
2.相关SQL关键字
start transaction;
rollback;
commit;
savepoint;
3.相关重要概念
脏读、幻读、不可重复读、MVCC多版本控制...
django orm提供了至少三种开启事务的方式
- 方式1:配置文件的数据库相关配置中添加键值对
全局有效 "ATOMIC_REQUESTS": True ps:每次请求所涉及到的orm操作同属于一个事务
- 方式2:装饰器
局部有效,这个视图函数内的一些orm操作属于一个事务 from django.db import transaction @transaction.atomic def index():pass
- 方式3:with上下文管理
局部有效,写在with下方的orm操作属于一个事务 from django.db import transaction def reg(): with transaction.atomic(): pass
ps:这里的三种方法有个小区别,前面两种方式执行事务,遇到返回值类型不对,orm操作雀食是可以正常执行的,但是with上下文管理的方式操作事务的话,则不行,操作会回退。
四、ORM常用字段类型
名称 | 含义 |
---|---|
AutoField() | Int自增列 必须填入参数 primary_key=True 当model中如果没有自增列 则自动会创建一个列名为id的列 |
CharField() | 字符类型 必须提供max_length参数 max_length表示字符长度 |
IntegerField() | 一个整数类型 范围在 -2147483648 to 2147483647 (一般不用它来存手机号(位数也不够) 直接用字符串存) |
BigIntegerField() | 长整型(有符号的) -9223372036854775808 ~ 9223372036854775807 |
DateField() | 日期字段 日期格式 YYYY-MM-DD 相当于Python中的datetime.date()实例 |
DateTimeField() | 日期时间字段 格式 YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] 相当于Python中的datetime.datetime()实例 |
DecimalField() | 10进制小数 参数 max_digits 小数总长度 decimal_places,小数位长度 |
EmailField() | 字符串类型 Django Admin以及ModelForm中提供验证机制 |
BooleanField() | 布尔值类型 传布尔值存数字0或1 |
TextField() | 文本类型 存储大段文本 |
FileField() | 字符串 路径保存在数据库 文件上传到指定目录 |
参数 upload_to = " " 上传文件的保存路径 | |
storage = None 存储组件 默认django.core.files.storage.FileSystemStorage | |
ForeignKey() | 外键类型在ORM中用来表示外键关联关系 一般把ForeignKey字段设置在 '一对多’中’多’的一方 ForeignKey可以和其他表做关联关系同时也可以和自身做关联关系 |
OneToOneField() | 一对一字段 通常一对一字段用来扩展已有字段 通俗的说就是一个人的所有信息不是放在一张表里面的,简单的信息一张表,隐私的信息另一张表,之间通过一对一外键关联 |
ManyToManyField() | 简单来说就是在多对多表关系并且这一张多对多的关系表是有Django自动帮你建的情况下 下面的方法才可使用create add set remove clear |
ORM还支持用户自定义字段类型,比方说ORM中没有设置char类型的字段,我们可以使用自定义字段来实现他。 |
class MyCharField(models.Field): def __init__(self, max_length, *args, **kwargs): self.max_length = max_length super().__init__(max_length=max_length, *args, **kwargs) def db_type(self, connection): return 'char(%s)' % self.max_length 这里是调用我们定义的字段类型 class User(models.Model): name = models.CharField(max_length=32) info = MyCharField(max_length=64)
五、ORM常用字段参数
名称 | 含义 |
---|---|
primary_key | 主键 |
verbose_name | 注释 |
max_length | 字段长度 |
max_digits | 小数总共多少位 |
decimal_places | 小数点后面的位数 |
auto_now | 每次操作数据自动更新事件 |
auto_now_add | 首次创建自动更新事件后续不自动更新 |
null | 允许字段为空 |
default | 字段默认值 |
unique | 唯一值 |
db_index | 给字段添加索引 |
choices | 当某个字段的可能性能够被列举完全的情况下使用。如:性别、学历、工作状态、. |
to | 关联表 |
to_field | 关联字段(不写默认关联数据主键) |
on_delete | 当删除关联表中的数据时,当前表与其关联的行的行为。 |
需要特别拿出来讲的是关联表时用的字段参数:
on_delete
它的值决定了关联表之前的关联操作行为
这里是代码使用展示
def func(): return 10 class MyModel(models.Model): user = models.ForeignKey( to="User", to_field="id", on_delete=models.SET(func) )
不同的值对应的功能
1、models.CASCADE 级联操作,当主表中被连接的一条数据删除时,从表中所有与之关联的数据同时被删除 2、models.SET_NULL 当主表中的一行数据删除时,从表中所有与之关联的数据的相关字段设置为null,此时注意定义外键时,这个字段必须可以允许为空 3、models.PROTECT 当主表中的一行数据删除时,由于从表中相关字段是受保护的外键,所以都不允许删除 4、models.SET_DEFAULT 当主表中的一行数据删除时,从表中所有相关的数据的关联字段设置为默认值,此时注意定义外键时,这个外键字段应该有一个默认值 5、models.SET() 当主表中的一条数据删除时,从表中所有的关联数据字段设置为SET()中设置的值,与models.SET_DEFAULT相似,只不过此时从表中的相关字段不需要设置default参数 6、models.DO_NOTHING 什么都不做,一切都看数据库级别的约束,注数据库级别的默认约束为RESTRICT,这个约束与django中的models.PROTECT相似
choices
当字段数据的可能性是可以完全列举出来的时候 应该考虑使用该参数
class UserInfo(models.Model): username = models.CharField(max_length=32) gender_choice = ( (1, '男性'), (2, '女性'), (3, 'other'), ) gender = models.IntegerField(choices=gender_choice) user_obj = models.UserInfo.objects.filter(pk=1).first() print(user_obj.gender) # 获取的是真实数据 print(user_obj.get_gender_display()) user_obj1 = models.UserInfo.objects.filter(pk=2).first() user_obj2 = models.UserInfo.objects.filter(pk=3).first() user_obj3 = models.UserInfo.objects.filter(pk=4).first() print(user_obj1.get_gender_display()) print(user_obj2.get_gender_display()) print(user_obj3.get_gender_display()) # 如果没有则按照真实数据返回
案例
六、多对多三种创建方式
- 1.全自动创建
class Book(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Author') class Author(models.Model): name = models.CharField(max_length=32)
优势:自动创建第三张表 并且提供了add、remove、set、clear四种操作
劣势:第三张表无法创建更多的字段 扩展性较差
- 2.纯手动创建
class Book(models.Model): title = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') others = models.CharField(max_length=32) join_time = models.DateField(auto_now_add=True)
优势:第三张表完全由自己创建 扩展性强
劣势:编写繁琐 并且不再支持add、remove、set、clear以及正反向概念
- 3.半自动创建
class Book(models.Model): title = models.CharField(max_length=32) authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author')) class Author(models.Model): name = models.CharField(max_length=32) class Book2Author(models.Model): book = models.ForeignKey(to='Book', on_delete=models.CASCADE) author = models.ForeignKey(to='Author', on_delete=models.CASCADE) others = models.CharField(max_length=32) join_time = models.DateField(auto_now_add=True)
优势:第三张表完全由自己创建 扩展性强 正反向概念依然清晰可用
劣势:编写繁琐不再支持add、remove、set、clear
本文作者:Python学习之旅
本文链接:https://www.cnblogs.com/yuezongke/p/17372373.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步