今日内容概要
- 正反向查询进阶操作
- 聚合查询
- 分组查询
- F与Q查询
- ORM查询优化
- ORM常见字段类型
- ORM常见字段参数
- ORM事务操作
- 多对多三种创建方式详解
正反向查询进阶操作
正反向查询进阶操作
- 1.查询主键为1的书籍对应的出版社名称及书名
res = models.Publish.objects.filter(book__pk=1).values('name','book__title') # print(res)
- 2.查询主键为3的书籍对应的作者姓名及书名
res = models.Author.objects.filter(book__pk=1).values('name', 'book__title') # print(res)
- 3.查询jason的作者的电话号码和地址
res = models.AuthorDetail.objects.filter(author__name='jason').values('phone','addr') # print(res)
- 4.查询南方出版社出版的书籍名称和价格
res = models.Book.objects.filter(publish__name='南方出版社').values('title','price') # print(res)
- 5.查询jason写过的书的名称和日期
res = models.Book.objects.filter(authors__name='jason').values('title','publish_time') # print(res)
- 6.查询电话是110的作者姓名和年龄
res = models.Author.objects.filter(author_detail__phone=110).values('name','age') # print(res)
- 7.查询主键为1的书籍对应的作者电话号码
res = models.AuthorDetail.objects.filter(author__book__pk=1).values('phone') # print(res) res = models.Author.objects.filter(book__pk=1).values('author_detail__phone') print(res)
聚合查询
1.聚合函数
max、min、sum、avg、count
2.聚合查询from django.db.models import Max, Min, Sum, Avg, Count # 没有分组之前如果单纯的时候聚合函数 需要关键字aggregate res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk')) print(res)
分组查询
1.分组查询特性
(1)分组有一个特性,默认只能够直接获取分组的字段,其他字段需要使用方法;
(2)我们也可以忽略掉该特性,将sql_mode中only_full_group_by配置移除即可。
2.分组查询
- 示例1:统计每一本书的作者个数
res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num') print(res) res1 = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id','book_num') print(res1) """ 1.按照整条数据分组 models.Book.objects.annotate() 按照一条条书籍记录分组 2.按照表中某个字段分组() models.Book.objects.values('title').annotate() 按照annotate之前values括号>中指定的字段分组 """
- 示例2:统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price') print(res)
- 示例3:统计不止一个作者的图书
filter在annotate前面则是where 在annotate后面则是having
res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num') print(res)
- 示例4:查询各个作者出的书的总价格
res = models.Author.objects.annotate(book_sum_price = Sum('book__price')).values('name','book_sum_price') print(res)
F与Q查询
1.补充
当表中已经有数据的情况下,添加新的字段需要指定一些参数:
- 设置字段值允许为空
null = True
- 设置字段默认值
default = 1000(默认值)
- 在终端直接给出默认值
1 provide a default value
2.F查询
F查询:查询条件不是自定义的而是来自于表中其他字段
首先先导入模块:from django.db.models import F
- 1.查询库存数大于卖出数的书籍
res = models.Book.objects.filter(storage_num__gt=F('sale_num')) print(res)
- 2.将所有书籍的价格上涨1000块
models.Book.objects.update(price=F('price') + 1000)
- 3.将所有书籍名称加上爆款后缀
models.Book.objects.filter(pk=5).update(title=F('title') + '爆款') # 针对字符串数据无法直接拼接 会报错,需要再到一个模块!!! from django.db.models.functions import Concat from django.db.models import Value ret3 = models.Book.objects.filter(pk=5).update(title=Concat(F('title'), Value('爆款')))
3.Q查询(可以改变filter括号内多个条件之间的逻辑运算符,还可以将查询条件的字段改为字符串形式)
filter() 等方法中逗号隔开的条件是与的关系。 如果你需要执行更复杂的查询(例如OR语句),你可以使用Q对象。
- 你可以组合& 和| 操作符以及使用括号进行分组来编写任意复杂的Q 对象。
from django.db.models import Q # 查询书籍名称是python入门或者价格是544.44的书 modelsBook.objects.filter(Q(title='python入门')|Q(price=544.44))
- 同时,Q 对象可以使用" ~ "操作符取反,这允许组合正常的查询和取反(NOT/非) 查询。
# 查询书籍名称不是python入门或价格不是544.44的书 models.Book.objects.filter(~Q(title='python入门')|Q(price=54)) Q查询进阶 models.Book.objects.filter(Q(title="linux") | Q(price=123))
- 上面的方式查询条件只能是字段名。如果我们只有字符串怎么写呢?
查询条件由用户输入决定q = Q() # 实例化一个Q对象 q.connector = 'or' #将默认and,改为or q.children.append(('title','python')) q.children.append(('kucun',666)) res = models.Book.objects.filter(q)
ORM查询优化
1.ORM查询特性
(1)django orm默认都是惰性查询
当orm的语句在后续的代码中真正需要使用的时候才会执行
(2)django orm自带limit分页
减轻数据库端以及服务端的压力
2.ORM表查询优化之only与defer
res = models.Book.objects.only('title','price') for obj in res: print(obj.title) print(obj.price) print(obj.publish_time) """ only会将括号内填写的字段封装成一个个数据对象 对象在点击的时候不会再走数据库查询 但是对象也可以点击括号内没有的字段 只不过每次都会走数据库查询 """ res = models.Book.objects.defer('title', 'price') for obj in res: # print(obj.title) # print(obj.price) print(obj.publish_time) """ defer与only刚好相反 数据对象点击括号内出现的字段 每次都会走数据库查询 数据对象点击括号内没有的字典 不会走数据库查询 """
3.ORM查询优化之select_related与prefetch_related
res = models.Book.objects.all() for obj in res: print(obj.publi sh.name) # 频繁走数据库查询 res = models.Book.objects.select_related('authors') """ select_related括号内只能接收外键字段(一对多 一对一) 自动连表 得出的数据对象在点击表中数据的时候都不会再走数据库查询 """ for obj in res: print(obj.publish.name) """ prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的 """ res = models.Book.objects.prefetch_related('publish') for obj in res: print(obj.publish.name)
事务操作
1.事务: ACID
2.事务隔离级别:
脏读 幻读 不可重复读 …
3.原生SQL:start transaction\rollback\commit\savepoint
4.orm中使用事务
导入transaction模块。
from django.db import transaction try: with transaction.atomic(): pass # 多条ORM语句 except Exception as e: print(e)
模型层常见字段
1.常见模型字段
1、models.AutoField 自增列= int(11) 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。 2、models.CharField 字符串字段 必须 max_length 参数 3、models.BooleanField 布尔类型=tinyint(1) 不能为空,Blank=True 4、models.ComaSeparatedIntegerField 用逗号分割的数字=varchar 继承CharField,所以必须 max_lenght 参数 5、models.DateField 日期类型 date 对于参数,auto_now =True则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。 6、models.DateTimeField 日期类型 datetime 同DateField的参数 7、models.DecimalField 十进制小数类型= decimal 必须指定整数位max_digits和小数位decimal_places 8、models.EmailField 字符串类型(正则表达式邮箱)=varchar 对字符串进行正则表达式 9、models.FloatField 浮点类型= double 10、models.IntegerField 整形 11、models.BigIntegerField 长整形 integer_field_ranges ={ 'SmallIntegerField':(-32768,32767), 'IntegerField':(-2147483648,2147483647), 'BigIntegerField':(-9223372036854775808,9223372036854775807), 'PositiveSmallIntegerField':(0,32767), 'PositiveIntegerField':(0,2147483647), } 12、models.IPAddressField 字符串类型(ip4正则表达式) 13、models.GenericIPAddressField 字符串类型(ip4和ip6是可选的) 参数protocol可以是:both、ipv4、ipv6 验证时,会根据设置报错 14、models.NullBooleanField 允许为空的布尔类型 15、models.PositiveIntegerFiel 正Integer 16、models.PositiveSmallIntegerField 正smallInteger 17、models.SlugField 减号、下划线、字母、数字 18、models.SmallIntegerField 数字 数据库中的字段有:tinyint、smallint、int、bigint 19、models.TextField 字符串=longtext 20、models.TimeField 时间 HH:MM[:ss[.uuuuuu]] 21、models.URLField 字符串,地址正则表达式 22、models.BinaryField 二进制 23、models.ImageField 图片 24、models.FilePathField 文件
2.ORM还支持自定义字段
自定义char字段
from django.db import models #Django中没有对应的char类型字段,但是我们可以自己创建 class MyCharField(models.Field): ''' 自定义的char类型的字段类 ''' 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): ''' 限定生成的数据库表字段类型char,长度为max_length指定的值 :param connection: :return: ''' return 'char(%s)'%self.max_length
3.ORM字段与MySQL字段对应关系:
'AutoField': 'integer AUTO_INCREMENT', 'BigAutoField': 'bigint AUTO_INCREMENT', 'BinaryField': 'longblob', 'BooleanField': 'bool', 'CharField': 'varchar(%(max_length)s)', 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 'DateField': 'date', 'DateTimeField': 'datetime', 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 'DurationField': 'bigint', 'FileField': 'varchar(%(max_length)s)', 'FilePathField': 'varchar(%(max_length)s)', 'FloatField': 'double precision', 'IntegerField': 'integer', 'BigIntegerField': 'bigint', 'IPAddressField': 'char(15)', 'GenericIPAddressField': 'char(39)', 'NullBooleanField': 'bool', 'OneToOneField': 'integer', 'PositiveIntegerField': 'integer UNSIGNED', 'PositiveSmallIntegerField': 'smallint UNSIGNED', 'SlugField': 'varchar(%(max_length)s)', 'SmallIntegerField': 'smallint', 'TextField': 'longtext', 'TimeField': 'time', 'UUIDField': 'char(32)',
ORM常见字段参数
1.常见字段参数
1、null=True 数据库中字段是否可以为空 2、blank=True django的Admin中添加数据时是否可允许空值 3、primary_key =False 主键,对AutoField设置主键后,就会代替原来的自增 id 列 4、auto_now 和 auto_now_add auto_now 自动创建---无论添加或修改,都是当前操作的时间 auto_now_add 自动创建---永远是创建时的时间 5、choices GENDER_CHOICE =( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = >GENDER_CHOICE) #字段模板展示 6、max_length 最大长度 7、default 默认值 8、verbose_name Admin中字段的显示名称 9、name|db_column 数据库中的字段名称 10、unique=True 不允许重复 11、db_index =True 数据库索引 12、editable=True 在Admin里是否可编辑 13、error_messages=None 错误提示 14、auto_created=False 自动创建 15、help_text 在Admin中提示帮助信息 16、validators=[] 验证器 17、upload-to 重定义上传文件的路径前缀 18.choices 当字段数据的可能性是可以完全列举出来的时候 应该考虑使用该参数 性别 学历 成绩 ```python class UserInfo(models.Model): username = models.CharField(max_length=32) gender_choice = ( (1, '男性'), (2, '女性'), (3, '其他'), ) gender = models.IntegerField(choices=gender_choice) userinfo_obj.get_gender_display()
2.外键字段相关参数
to # 设置要关联的表 to_field # 设置要关联的表的字段 related_name # 改变正反向查询 on_delete # 级联删除
3.设置级联相关的操作
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相似
多对多三种创建方式
1.自动创建
authors = models.ManyToManyField(to='Author') 优点:第三张表自动创建 缺点:第三张表扩展性差
2.2.手动创建
class Book(models.Model): pass class Author(models.Model): pass class Book2Author(models.Model): book_id = models.ForeignKey(to="Book") author_id = models.ForeignKey(to="Author") 优点:第三张表扩展性强 缺点:无法使用正反向查询以及多对多四个方法(add;remove,等)
3.半自动创建
class Book(models.Model): authors = models.ManyToManyField(to='Author', through='Book2Author' through_fields=('book_id','author_id') ) class Author(models.Model): pass class Book2Author(models.Model): book_id = models.ForeignKey(to="Book") author_id = models.ForeignKey(to="Author") 优点:扩展性强并且支持正反向查询 缺点:无法使用多对多四个方法