一、聚合查询与aggregate方法
1、聚合查询通常都是配合分组查询一起使用的,若需单独使用,要通过aggregate方法。
2、需要导入的模块:
from django.db.models import Max, Min, Sum, Count, Avg
3、实例:
task_obj_set = models.Task.objects.all() print(task_obj_set.aggregate(Max('time_limit'))) # 最大值 print(task_obj_set.aggregate(Min('time_limit'))) # 最小值 print(task_obj_set.aggregate(Sum('time_limit'))) # 值之和 print(task_obj_set.aggregate(Count('time_limit'))) # 值个数 print(task_obj_set.aggregate(Avg('time_limit'))) # 值的均数 # 也可以把多个聚合函数写在一个aggregate()里面
二、分组查询---annotate方法
1、实例:
# 一、统计每个task的hunter的个数 task_obj_set = models.Task.objects.all() # 不作其他声明,默认每个记录是一组 # 需要给聚合查询的结果绑定一个名字,后续可以以该名字查询 print(task_obj_set.annotate(hunter_num=Count('hunter__pk')).values('area', 'hunter_num')) # __pk 也可以省略不写,效果一样 print(task_obj_set.annotate(hunter_num=Count('hunter')).values('time_limit', 'hunter_num')) # 二、统计每个level的hunter的more_info的real_age最大值 level_obj_set = models.Level.objects.all() print(level_obj_set.annotate(max_real_age=Max('hunter__more_info__real_age')).values('name', 'max_real_age')) # 三、统计每个hunter的task的time_limit的平均数大于等于72的具体值 hunter_obj_set = models.Hunter.objects.all() print(hunter_obj_set.annotate(avg_time=Avg('task__time_limit')).filter(avg_time__gt=72).values('code_name', 'avg_time'))
2、按照指定字段分组:
# hunter_moro_info的real_age相同的为一组,统计每组的hunter的task的的time_limit之和 hunter_more_info_obj_set_by_real_age = models.HunterMoreInfo.objects.values('real_age') print(hunter_more_info_obj_set_by_real_age.annotate(sum_time=Sum('hunter__task__time_limit')).values('real_name', 'sum_time'))
三、F查询
1、通过F查询可以直接获取某个字段对应的记录。
2、需要导入的模块:
from django.db.models import F
3、实例:
# 一、查找hunter的look_age比out_age大的more_info的real_name和real_age hunter_obj_set = models.Hunter.objects.all() print(hunter_obj_set.filter(look_age__gt=F('out_age')).values('more_info__real_name', 'more_info__real_age')) # 二、将所有task的time_limit增加24 task_obj_set = models.Task.objects.all() task_obj_set.update(time_limit=F('time_limit') + 24)
4、F查询配合Concat与Value功能实现字符串拼接:
①需要导入的模块:
from django.db.models.functions import Concat from django.db.models import Value
②实例:
level_obj_set = models.Level.objects.all() level_obj_set.update(right=Concat(Value('权限:'), F('right')))
四、Q查询
1、打破只能用逗号进行与运算的限制,可以通过Q查询可以进行更多的关系运算。
2、需要导入的模块:
from django.db.models import Q
3、实例:
hunter_obj_set = models.Hunter.objects.all() # 一、查询hunter的out_age大于等于18,且小于等于20的code_name和out_age # 逗号---and print(hunter_obj_set.filter(Q(out_age__gte=18), Q(out_age__lte=20)).values('code_name', 'out_age')) # 二、查询hunter的out_age小于18,或大于20的code_name和out_age # 竖杠---or print(hunter_obj_set.filter(Q(out_age__lt=18) | Q(out_age__gt=20)).values('code_name', 'out_age')) # 三、查询hunter的out_age不在20到100之间的code_name和out_age # 波浪号---not print(hunter_obj_set.filter(~Q(out_age__range=[20, 100])).values('code_name', 'out_age'))
4、Q查询对象化的用法:
# 查询hunter的'out_age'小于20,或'look_age'大于50的code_name,查询条件必须是字符串 hunter_obj_set = models.Hunter.objects.all() # 方式一 # 先生成两个Q查询对象 q_obj_1 = Q() q_obj_2 = Q() q_obj_1.children.append(('out_age__lt', 20)) q_obj_2.children.append(('look_age__gt', 50)) # 再把对象作为条件查询 print(hunter_obj_set.filter(q_obj_1 | q_obj_2).values('code_name')) # 方式二 # 用同一个Q查询对象,修改内部默认子条件关系运算的符号 q_obj_3 = Q() q_obj_3.connector = 'or' # 默认 'and' q_obj_3.children.append(('out_age__lt', 20)) q_obj_3.children.append(('look_age__gt', 50)) print(hunter_obj_set.filter(q_obj_3).values('code_name'))
五、开启事务
1、需要导入的模块:
from django.db import transaction
2、基本语句结构:
try: # with 代码块内的orm语句同属于一个事务 with transaction.atomic(): # orm语句1 # orm语句2 pass except Exception as e: print(e)
六、常用字段及参数汇总
1、通用参数:
①verbose_name:字段的描述。
②db_index:将该字段设置为索引。
2、AutoField:一般用于主键字段,且一般 也不手动创建,orm会自动以'id'为名,创建主键字段。
①primary_key = True,设置为主键 。
3、CharField:不定长字符串。
①max_length:最大长度。
4、IntegerField:整型。
5、BigIntegerField:长整型。
6、DecimalField:浮点型。
①max_digits:最大总长。
②decimal_places:小数部分固定长度。
7、EmailField:邮箱格式字符串。
8、DateField:日期格式,年月日。
9、DateTimeField:日期格式,年月日时分秒。
①auto_now=True,动态值,每次修改记录会自动更新为当时的时间。
②auto_now_add=True,固定值,记录创建数据时时候,后续不会再更改。
10、BooleanField:布尔型,True/False 对应到数据库会转化为 1/0。
11、TextField:长字符串,可以接收大段长文本,没有长度限制。
12、FileField:文件类型。
①upload_to='xxxooo tt',给该字段传一个文件对象,会将文件数据保存于该目录下,另外将文件路径保存到数据库中。
13、更多字段详情,参考鸡哥博客:https://www.cnblogs.com/Dominic-Ji/p/9203990.html。
14、自定义字段,在models.py中:
class MyField(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({})'.format(self.max_length) class Xoo(models.Model): name = MyField(max_length=100, null=True, verbose_name='测试')
16、OneToOneField:一对一字段。
17、ManyToManyField:多对多字段。
18、ForeignKey:外键字段,默认一对多。
①unique=True:设置成一对一,效果等同于OneToOneField。
②to_field:设置关联表的关联字段,一般不设置,就是默认关联主键。
③on_update/on_delete:设置当关联表更新/删除关联的记录记录时,本表对应的行为,在django2.0+/3.0+中需要通过此参数设置为级联更新/删除,而1.0+是默认级联更新/删除的。
七、数据库查询优化
1、only与defer:
①models.Book.objects.all():一次性从数据库获得完整的记录对象集,可以通过记录对象查看任意字段,不需要再访问数据库。
②models.Book.objects.only('xxx'):从数据库获得的记录对象集,只携带了'xxx'字段的记录,只有查看'xxx'字段不需要再访问数据库,查其他字段还需要重新访问数据库。
③models.Book.objects.defer('xxx'):从数据库获得的记录对象集,携带了除'xxx'字段的以外的其他所有记录,只有查看'xxx'字段才需要重新访问数据库,查其他字段则不需要再访问数据库。
④小结:使用哪种方法能够更节约io时间,需要看表的字段个数以及每个字段的记录多少等综合考虑。
2、select_related与prefetch_related:
①models.Hunter.objects.all().select_related('level'):先连表,类似于获得大表对象,后续对大表对象中的所有字段的查询都不需要再访问数据库。
②models.Hunter.objects.all().prefetch_related('task'):子查询,比连表会多访问一次数据库。
③小结:使用哪种方法能够更节约io时间,需要综合比较连表的时间和额外访问数据库的时间。