• day65 django进阶(1)


    一、聚合查询与分组查询

    1 聚合查询(aggregate)

    ps:通常情况下聚合查询都是配合分组查询一起使用的

    # django中与数据库相关的模块基本都在django.db.models里或者在django.db里
    from django.db.models import Max,Min,Sum,Count,Avg
    
    # 查询所有书的平均价格
    res = models.Book.objects.aggregate(Avg('price'))
    
    # 也可以联合使用
     res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price'))
    

    2 分组查询(annotate)

    分组在mysql类似于group by,分组之后默认只能拿到分组的数据。

    如果报错,可能是严格模式的问题,设置一下 ONLY_FULL_GROUP_BY即可

    # 统计每一个作者写了几本书
    obj = models.Author.objects.annotate(count_book=Count('book')).values('name','count_book')
    
    
    # 统计每本书有几个作者
    obj = models.Book.objects.annotate(author_count=Count('authors')).values('title','author_count')
    
    
    # 统计每个出版社最便宜的书
    obj = models.Publish.objects.annotate(cheaper_book=Min('book__price')).values('name','cheaper_book')
    
    
    # 统计作者不止一个的书籍
    obj = models.Book.objects.annotate(author_num = Count('authors')).filter(author_num__gt=1).values('title','author_num')
    
    # 统计每个作者写的书的总价格
    obj = models.Author.objects.annotate(sum_price = Sum('book__price')).values('name','sum_price')
    
    

    上述查询对应的mysql语句

    # 查询每个出版社最便宜的书
    SELECT
    	app01_publish.NAME,
    	min( price ) 
    FROM
    	app01_publish
    	JOIN app01_book ON app01_publish.id = app01_book.publish_id 
    GROUP BY
    	publish_id
    	
    # 统计每个作者有几本书
    SELECT
    	app01_author.NAME,
    	COUNT( app01_book_authors.book_id ) 
    FROM
    	app01_author
    	JOIN app01_book_authors ON app01_author.id = app01_book_authors.author_id 
    GROUP BY
    	app01_author.id
    	
    # 统计每本书有几个作者
    SELECT
    	app01_book.title,
    	count( app01_book_authors.author_id ) AS count_authors 
    FROM
    	app01_book
    	JOIN app01_book_authors ON app01_book.id = app01_book_authors.book_id 
    GROUP BY
    	app01_book.id
    	
    # 查询作者数大于一的书籍
    SELECT
    	title,
    	count( app01_book_authors.author_id ) AS author_num 
    FROM
    	app01_book
    	JOIN app01_book_authors ON app01_book.id = app01_book_authors.book_id 
    GROUP BY
    	app01_book.id 
    HAVING
    	count( app01_book_authors.author_id )>1
    	
    # 统计每个作者的书的总价格
    SELECT
    	app01_author.NAME,
    	sum( app01_book.price ) 
    FROM
    	app01_author
    	JOIN app01_book_authors ON app01_author.id = app01_book_authors.author_id
    	JOIN app01_book ON app01_book_authors.book_id = app01_book.id 
    GROUP BY
    	app01_author.id
    

    二、F与Q查询

    1 F查询的三个功能

    1.1 能帮助我们直接获取到表中某个字段对应的数据

    from django.db.models import F
    
    # 1 查寻卖出数大于库存数的书籍
    
    models.Book.objects.filter(maichu__gt=F('kucun'))
    

    1.2 获取一个整形字段的数据进行运算

    models.Book.objects.filter.update(price=F('price')+500)
    

    1.3 获取一个字符串字段进行拼接

    from django.db.models.functions import Concat
    from django.db.models import Value
    models.Book.object.update(title=Concat(F('title'),Value('爆款')))
    # 如果不按照这种方法直接用数字那样加减的话,所有名称会都变成空白
    

    2 Q查询

    2.1 修改查询之间的关系

    from django.db.models import Q
    
    # 默认情况下filter内部的条件用,隔开,逗号表示and关系,如果要修改这个关系只能用Q查询来做
    models.Book.objects.filter(id__gt=1, price__lt=2000)
    
    # 在Q查询中逗号也是表示为and关系
    models.Book.objects.filter(Q(id__gt=1), Q(price__lt=2000))
    
    # 查询id>2或者价格<2000的书籍  |为or
    models.Book.object.filter(Q(id__gt=2)|Q(price__lt=2000))
    
    # 查询id不大于3或者价格小于600的书籍  ~为not
    models.Book.objects.filter(~Q(id__gt=3)|Q(price__lt=600))  
    

    2.2 Q查询的高阶用法

    q = Q() # 实例化一个Q对象
    q.connector = 'or' # 设置默认关系为or,不设置的话为and
    q.children.append(('maichu__gt',100)) # 添加查询条件,第一个为字段查询条件,第二个为参数
    q.children.append(('price__lt',600))
    res = models.Book.objects.filter(q)  
    print(res)
    

    三、事务

    """
    事务
    	ACID
    		原子性
    			不可分割的最小单位
    		一致性
    			跟原子性是相辅相成
    		隔离性
    			事务之间互相不干扰
    		持久性
    			事务一旦确认永久生效
    	
    	事务的回滚 
    		rollback
    	事务的确认
    		commit
    """
    # 目前你只需要掌握Django中如何简单的开启事务
    # 事务
        from django.db import transaction
        try:
            with transaction.atomic():
                # sql1
                # sql2
                ...
                # 在with代码快内书写的所有orm操作都是属于同一个事务
        except Exception as e:
            print(e)
        print('执行其他操作')
    

    四、orm中常用的字段及参数

    1 基本字段

    # 一些全都有的参数,verbose_name 字段的注释,defalut 默认值,null=True/False 是否允许为空
    
    # 主键字段
    AutoField(primary_key=True)
    
    # 字符字段 varchar(最大长度255)
    CharField(max_length=32) 
    
    # 整形字段 int
    IntegerField()
    
    # 长整形 bigint
    BigIntegerField()
    
    # 浮点型 float
    DecimalField(max_digts=8(最大长度,包括小数),decimal_places=2(小数部分长度))
    
    # 邮箱 varchar(254)
    EmailFiled
    
    # 日期类型 date  
    DateField
    
    # 精确日期类型 datetime
    DateTimeField
    
    # 日期类型的参数:
    # auto_now:每次修改数据的时候都会自动更新当前时间
    # auto_now_add:只在创建数据的时候记录创建时间,后续不会自动修改
    
    # 布尔值
    BooleanField  # 数据里面存0/1
    
    # 文本类型
    TextField # 可以存放大量文本内容,没有字数限制
    
    # 文件类型   -字符类型
    FileField(upload_to='文件保存的路径')
    # 会给该字段穿一个文件对象,把文件本身自动保存到路径下,这个字段内保存的是文件路径
    
    # 更多字段
    直接参考博客:https://www.cnblogs.com/Dominic-Ji/p/9203990.html
    

    2 自定义字段

    # django除了给你提供了很多字段类型之外 还支持你自定义字段
    class MyCharField(models.Field):
        def __init__(self,max_length,*args,**kwargs):
            # 这里添加我们对其设置的默认关系
            self.max_length = max_length
            # 调用父类的init方法
            super().__init__(max_length=max_length,*args,**kwargs)  # 一定要是关键字的形式传入
    
        def db_type(self, connection):
            """
            返回真正的数据类型及各种约束条件
            :param connection:
            :return:
            """
            return 'char(%s)'%self.max_length
    
    # 自定义字段使用
    myfield = MyCharField(max_length=16,null=True)
    

    3 外键字段及参数

    # 当外键字段唯一的时候就成了一对一关系
    ForeignKey(unique=True)   ===	OneToOneField()
    
    # db_index = True 代表这个字段设置为索引
    
    # to_field 设置要关联的表的字段,默认不写就是关联另外一张的主键字段
    
    # on_delete 当删除关联表的数据时,对当前表关联的行为
    
    # django2.X以上需要指定级联更新和级联删除
    

    五、数据库查询优化

    orm语句的特点:惰性查询,如果只写的orm语句,后续没有使用,orm会自动识别,直接不执行

    res = models.Book.object.all() # 这个语句不会执行因为这一行还没用到
    print(res) # 用到了才会去执行上面代码
    

    1 only与defer

    # 普通取一个字段
    
    res = models.Book.object.values('title').first()
    print(res.get('title'))
    
    # values会限定只取固定字段,取没有的就是空,only更加灵活
    
    # only取一个字段
    
    res = models.Book.objects.only('title').first()
    print(res.title)
    
    # only的限定,相当于只从数据库里读取了很小一部分的数据,这里的res=取出来的title,优化了我们查询的速度,如果我们点其他字段就会重新到数据库中去查
    
    # defer与only恰恰相反,除了得到的返回值还是括号内的字段结果
    
    # 这种优化作用于跨表查询
    
    res = models.Book.objects.all()
    for obj in res:
    	print(obj.publish.name) # 这里没循环一次都要走一次数据库查询
    	
    res = models.Book.objects.select_related('authors')
    # select_related默认内部会先把book和publish连起来,然后一次性把大表里的所有数据全都分装起来给对象,这个时候无论是点击book表还是publish表都不会走数据库查询了,相当于mysql中的join
    
    # 特别的是,select_related括号内只能放外键字段  一对多,一对一
    # 多对多不行
    
    # prefetch_related内部就是子查询,把查询出来的结果全都封装给对象
     res = models.Book.objects.prefetch_related('publish')
    
  • 相关阅读:
    队列数据结构与算法JavaScript描述(5)
    栈数据结构与算法Javascript描述(4)
    散列数据结构与算法JavaScript描述(8)
    Evevt Loop、任务队列、定时器等
    OSGi初始篇
    应用服务平台与应用服务器
    数据源相关规范整理
    新手入门:教您最优的J2EE学习经验和流程
    TableView的使用
    Strategy
  • 原文地址:https://www.cnblogs.com/hz2lxt/p/13034162.html
Copyright © 2020-2023  润新知