聚合查询,分组查询,F与Q查询,ORM查询优化,模型层常见字段类型,ORM自定义字段多对多三种创建方式

  • 聚合查询

  • 分组查询

  • F与Q查询

    • F查询

    • Q查询

  • ORM查询优化

    • only

    • defer

    • select_related

    • prefetch_related

  • 事务操作

  • 模型层常见字段

  • ORM常见字段参数

    • orm支持自定义字段

  • 多对多三种创建方式

    • 自动创建

    • 手动创建

    • 半自动创建


聚合查询

聚合查询关键字

  max  min  sum  avg  count

  from django.db.models import Max, Min, Sum, Avg, Count

在没有分组之前如果单纯的使用聚合函数,需要借助关键字aggregate

eg:

res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Avg('price'),Count('pk'))
print(res)

在用 Count的时候最好用id这种有标识性的字段


分组查询

关键字:annotate

分组有一个特性:

  默认只能够直接获取分组的字段 其他字段需要使用方法

我们也可以忽略掉该特性 将sql_mode中only_full_group_by配置移除即可

1.按照整条数据分组

  按照一条条书籍记录分组

res = models.Book.objects.annotate(author_num=Count('authors__pk')).values('title', 'author_num')
print(res)

2.按照表中某个字段分组()

  按照annotate之前values括号中指定的字段分组

res = models.Book.objects.values('publish_id').annotate(book_num=Count('pk')).values('publish_id', 'book_num')
print(res)

统计不止一个作者的图书

res = models.Book.objects.annotate(author_num=Count('authors__pk')).filter(author_num__gt=1).values('title','author_num')
# print(res)

filter在annotate前面则是where

filter在annotate后面则是having


F与Q查询

F查询

F查询:   查询条件不是自定义的而是来自于表中其他字段(就是说用的都是字段名)

from django.db.models import F

eg:查询库存数大于卖出数的书籍

res = models.Book.objects.filter(strong_num__gt=F('sale_num'))
print(res)

将所有书籍的价格上涨1000块

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

将所有书籍名称加上爆款后缀

但是字符串无法直接拼接, 需要用到Concat(字符串拼接),Value(值)模块

from django.db.models.functions import Concat
from django.db.models import Value

res = models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
print(res)

补充:

当表中已经有数据的情况下 添加新的字段需要指定一些参数
    1.设置字段值允许为空         null=True
    2.设置字段默认值             default=1000
    3.在终端中直接给出默认值      1 provide a default value

Q查询

1. Q查询:可以改变fileter括号内多个条件之间的逻辑运算符

from django.db.models import Q

(条件,条件)    (Q(条件),Q(条件))这两种都是and关系

(Q(条件) | Q(条件))        管道符是or关系

(~Q(条件),Q(条件))       ~波浪号是not关系

2. Q查询:还可以将查询条件的字段改为字符串形式

  就是说我们可以从前端获取用户选择的条件,更加灵活

eg:

q_obj.children.append(('pk', 1))

将来'pk'就是我从前端获取的用户输入的条件,一旦符合我就可以执行1

3. Q是一个类,加括号调用就是一个对象

4. q_obj.connector = 'or' 

  q对象默认的多个条件也是and关系 可以修改为or


ORM查询优化 

 1. django orm默认都是惰性查询

  就是  当orm的语句在后续的代码中真正需要使用的时候才会执行

  比如说  res = orm语句   

  我去打印了res后面的orm语句才会执行sql代码

2. django orm自带分页功能

  减轻数据库端以及服务端的压力

only

  1. 我们如果使用values去拿数据,得到的只能是列表套字典的形式,如果想要拿到单独的字段值就只能用.get的方法

  2. 使用only就可以拿到列表套对象,这个时候就可以使用点去拿到单独的字段值

  3. 我们这个时候拿的是括号里的数据,如果想要拿到括号外的数据也是可以的。但是会有不同

总结:

  1. only会将括号内填写的字段封装成一个个数据对象,对象在点击的时候不会再走数据库查询

  2. 对象也可以点击括号外的字段,只不过每点一次就会走一次数据库查询

defer

 defer与only刚好相反

  1. 数据对象点击括号内出现的字段 每次都会走数据库查询

  2. 数据对象点击括号内没有的字典 不会走数据库查询

select_related

  1. select_related括号内只能接收外键字段(一对多 一对一) 自动连表

  2. 得出的数据对象在点击表中数据的时候都不会再走数据库查询

prefetch_related

1. prefetch_related底层其实是子查询 将查询之后的结果也一次性封装到数据对象中 用户在使用的时候是感觉不出来的

总结:

  1. orm优化是为了缓解数据库频繁查询使用的压力

  2. only和defer只适用于单表查询

  3. select_related和prefetch_related适用于多表查询

  4. only拿括号内字段值只会执行最基本的sql语句,而拿括号外的字段值每拿一条执行一条的sql查询语句

  5. defer的用法和3中的only相反

  6. select_related括号内只能接收外键字段(一对多  一对一)会自动将两张表拼起来,而且只会走一条基本的sql语句

  7. prefetch_related底层其实是子查询,将查询之后的结果也一次性封装到数据对象中

  8. 这几种方法各有优劣,根据实际场景使用


事务操作

回顾mysql事务

A原子性  C一致性  I隔离性  D持久性

事务   transaction  rollback  回滚   commit  刷新到硬盘(提交)  savepoint  保留点

脏读, 幻读  不可重复读  

事务日志

django事务   可以查看transaction源码

from django.db import transaction
try:
    with transaction.atomic():
        pass  # 多条ORM语句
except Exception as e:
        print(e)

模型层常见字段

AutoField()
CharField()
IntegerField()
BigIntegerField()
DateField()
DateTimeField()
DecimalField()
EmailField()
BooleanField()
	传布尔值存数字0或1
TextField()
	存储大段文本
FileField()
	存储文件数据  自动找指定位置存储 字段存具体路径
ForeignKey()
OneToOneField()
ManyToManyField()

orm支持自定义字段

自定义字段在实际项目应用中可能会经常用到,这里需要对他留个印象!

1. 直接继承models.Filed (Filed是来自models的)

class MyCharField(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):   定义db_type为你定义的字段类型
        return 'char(%s)' % self.max_length
info = MyCharField(max_length=32)

ORM常见字段参数

普通字段
max_length
verboses_name
auto_now
auto_now_add
null
default
max_digits
decimal_places
unique=True   唯一
db_index=True   索引   基于索引查询
choices  !!!
外键字段
to
to_field
related_name   起别名,在正反向查询的时候可以使用
on_delete

models.CASCADE 

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. 自动创建

  orm自动帮你创建第三张表

  authors = models.ManyToManyField(to='Author')

  优点:第三张表自动创建

  缺点:第三张表扩展性差

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  clear  update)

3. 半自动创建

第三张表还是自己创建,但是我们可以创建一个外键,不过这个外键要加上几个参数

    to='Author',   和谁关联

   through='Book2Author'   告诉orm这是自己创建的表,后续可以做正反向查询

   through_fields=('book_id','author_id') 告诉orm我是通过这几个字段作两个表之间的关联的

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")

  优点:扩展性强并且支持正反向查询

  缺点:无法使用多对多四个方法

 

posted @ 2022-09-06 20:59  没错,干就完了!  阅读(88)  评论(0)    收藏  举报