zoukankan      html  css  js  c++  java
  • 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')
    
  • 相关阅读:
    Yield Usage Understanding
    Deadclock on calling async methond
    How to generate file name according to datetime in bat command
    Run Unit API Testing Which Was Distributed To Multiple Test Agents
    druid的关键参数+数据库连接池运行原理
    修改idea打开新窗口的默认配置
    spring boot -thymeleaf-url
    @pathvariable和@RequestParam的区别
    spring boot -thymeleaf-域对象操作
    spring boot -thymeleaf-遍历list和map
  • 原文地址:https://www.cnblogs.com/hz2lxt/p/13034162.html
Copyright © 2011-2022 走看看