Django之模型层02

一、聚合查询与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时间,需要综合比较连表的时间和额外访问数据库的时间。

  

原文地址:https://www.cnblogs.com/caoyu080202201/p/13027384.html