django模型层详解

django模型层详解

内容概要

  • 测试环境配置

  • ORM常用关键字(重要)

  • ORM执行SQL语句

  • 神奇的双下线查询

  • ORM外键字段的创建

  • 外键字段数据的增删改查

  • 多表查询(基于对象的跨表查询、基于双下划线的跨表查询)

  • 聚合查询

  • 分组查询

  • F与Q查询

  1. 自带的sqlate3数据库对时间字段不敏感 有时候会展示错乱所以我们习惯切换成常见的数据库比如MYSQL
    django orm并不会帮我们创建数据库 所以需要我们自己提前创建好数据库

配置好settings文件数据库


DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djg07',
        'HOST': 'localhost',
        'PORT': 3306,
        'USER': 'root',
        'PASSWORD': 'root',
        'CHARTSET': 'utf8'
    }
}

准备好表

class User(models.Model):
    id = models.AutoField(primary_key=True, verbose_name='用户id')
    name = models.CharField(max_length=32, verbose_name='姓名')
    age = models.IntegerField(verbose_name='年龄')
    register_time = models.DateTimeField(verbose_name='注册时间', auto_now_add=True)

    # auto_now 是只要修改或添加就会把当前时间自动更新
    # auto_now_add  是在增加第一次创建数据时自动把当前时间添加到里面

    #  models.DateTimeField年月日时分秒时间 models.DateField 年月日时间

    def __str__(self):
        # 在打印类产生的方法时触发,只能返回字符串数据
        return f'对象:{self.name}'

image

django单独测试某个功能

  1. 单独测试django某个功能层
    默认不允许单独测试某个py文件
    image

  2. 如果想要测试某个py文件(主要models.py)

    #需要把这个放在最顶上
    import os
    import django
    
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django07.settings')
    django.setup()
    
    #测试的数据一定要放在他们下面,否则会跟上面报错一样无法正常测试
    from user import models
    
    models.User.objects.create(name='张三', age=18)
    

    image

  3. django orm底层还是SQL语句我们是可以查看的
    如果我们手上是一个QuerySet对象 那么可以直接点query查看SQL语句
    image

    但是有的orm提供的方法不是一个QuerySet对象,但是又想看SQL语句那么也可以在配置文件中添加日志记录的settings.py配置

    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'handlers': {
            'console':{
                'level':'DEBUG',
                'class':'logging.StreamHandler',
            },
        },
        'loggers': {
            'django.db.backends': {
                'handlers': ['console'],
                'propagate': True,
                'level':'DEBUG',
            },
        }
    }
    

image

ORM常用关键字(方法)

  1. 创建数据create() 创建数据并直接获取当前创建的数据对象

    res = models.User.objects.create(name='张三', age=18)
    print(res)
    res = models.User.objects.create(name='李四', age=28)
    print(res)
    res = models.User.objects.create(name='jason', age=18)
    print(res)
    res = models.User.objects.create(name='tom', age=38)
    print(res)
    res = models.User.objects.create(name='jerry', age=88)
    print(res)
    res = models.User.objects.create(name='ikun', age=58)
    print(res)
    

    image

  2. 筛选数据filter() 根据条件筛选数据 结果是QuerySet[对象1,对象2,···]

    res = models.User.objects.filter()  # 不写默认就算查所有字段
    print(res)
    res = models.User.objects.filter(name='jason')  # 写了就根据字段名与字段值查找数据
    print(res)
    res = models.User.objects.filter(name='jason',age=18)  # 可以写多个筛选条件,默认是and连接
    print(res)
    

    image

  3. first() last() QuerySet支持索引取值但是只能只正数 并且ORM不建议我们使用索引

    res = models.User.objects.filter()
    print(res[0])
    res = models.User.objects.filter(id=100)
    print(res[0])
    

    image

    # 无法执行
    res = models.User.objects.filter()
    print(res[-1])
    
        assert ((not isinstance(k, slice) and (k >= 0)) or
    AssertionError: Negative indexing is not supported.
    

    image

    使用first,与last去索引

    res = models.User.objects.filter()
    print(res.first())
    print(res.last())
    res = models.User.objects.filter(id=1000)
    print(res.first())  # 数据不存在索引取值也不会报错
    print(res.last())
    

    image

  4. 更新数据update (批量更新数据)

    models.User.objects.update()  # 批量更新数据
    res = models.User.objects.filter(id=1).update(name='托马斯')  # 手动筛选数据,在更新达到指定更新的效果
    print(res)  # update返回的是影响行数
    

    image

  5. 删除数据delete (批量删除)

    # models.User.objects.delete()  # 批量删除数据
    res = models.User.objects.filter(id=1).delete()
    # 手动筛选数据,进行删,我们一般都不会进行删除数据只会修改数据字段已达到删除的目的
    print(res)
    

    image

  6. 查询所有数据all 结果是QuerySet[对象1,对象2]

    res = models.User.objects.all()  # 查询所有数据django默认查询全部的时候,查21条,需要了在继续查
    print(res)
    

    image

  7. 获取字段数据values 结果是QuerySet[{},{},{}]

    res = models.User.objects.values()  # 获取所有数据字段所有值
        print(res)
        print(res.first().get('name'))  # 这里又重新查了一般数据库
        """
        (0.000) SELECT `user_user`.`id`, `user_user`.`name`, `user_user`.`age`, `user_user`.`register_time` FROM `user_user` ORDER BY `user_user`.`id` ASC  LIMIT 1; args=()
        """
        res = models.User.objects.all().values('name')  # 获取全部数据name字段
        print(res)
        res = models.User.objects.filter(id=4).values('name')  # 过滤数据后在获取name字段数据
        print(res)
    

    image

  8. values_list 根据指定字段获取数据结果QuerySet[(),(),()]

    res = models.User.objects.filter(id=3).values_list('name', 'age')
        print(res)
    

    image

  9. 去重distinct 数据一模一样才可以去重如果有主键肯定不行
    mysql数据库不支持,字段去重
    此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重。

    res = models.User.objects.values('name', 'age').distinct()
        print(res)
        """
        <QuerySet [{'name': '李四', 'age': 28}, {'name': 'jason', 'age': 18}, {'name': 'tom', 'age': 38}, 
        {'name': 'jerry', 'age': 88}, {'name': 'ikun', 'age': 58}]>
        """
        res = models.User.objects.values('name', 'age').distinct('age')  # mysql数据库不支持,字段去重
        print(res)
    

    image

  10. 排序oredr_by()

    res = models.User.objects.all().order_by('age','id')  # 默认为升序
        print(res)
        res = models.User.objects.all().order_by('-age','id')  # 字段前面加-号就是降序
        print(res)
    

    image

  11. get() 根据条件筛选数据并直接获取到对象一旦条件不存在会直接报错 不建议使用

    res = models.User.objects.get(pk=2)  # 有数据能查到,执行
    print(res)
    res = models.User.objects.get(pk=1)  # 没有数据查新报错
    print(res)
    

    image

  12. 取反操作exclude() 是除了当前指定筛选数据不查询,查询其他的

    res = models.User.objects.exclude(pk=2)  # 是除了当前指定筛选数据不查询,查询其他的
    print(res)
    res = models.User.objects.all()
    print(res)
    

    image

  13. reverse() 颠倒顺序(被操作的对象必须是已经排过序的才可以)

    res = models.User.objects.all().order_by('id').reverse()  # 颠倒排序
    print(res)
    res = models.User.objects.all().order_by('id')  # 升序
    print(res)
    res = models.User.objects.all().reverse() # 没有排序颠倒不生效
    print(res)
    

    image

  14. count() 统计结果中数据的个数

    res = models.User.objects.filter(age=18).count()  # 返回值为统计个数
        print(res)
    

    image

  15. exists() 判断结果集中是否含有数据 如果有则返回Ture 没有则返回False

    res = models.User.objects.all().exists()
    print(res)
    res = models.User.objects.filter(pk=100).exists()
    print(res)
    

    image

ORM执行SQL语句

有时候ORM操作效率可能片偏低我们可以自己编写SQL语句

方式1:raw()只能查数据

res = models.User.objects.raw('select * from user_user;')
print(res)         # 返回一个RawQuerySet对象
print(list(res))   # 拿出结果对象
print(res[0])      # 索引取值


# raw()无法执行增删改操作
# res = models.User.objects.raw('insert into user_user(name,age) values("1",2);')
# res = models.User.objects.raw('delete from user_user where id=8')
# res = models.User.objects.raw('update user_user set name="哈哈哈" where id=8')
# print(res)

image

方式2

from django.db import connection
import time
ctime = time.strftime("%Y-%m-%d %X")
curosrs = connection.cursor()
curosrs.execute('select * from user_user')
print(curosrs.fetchall())
# curosrs.execute('insert into user_user(name,age,register_time) value ("李李",50,%s)', (ctime,))
curosrs.execute('delete from user_user where id=9')
curosrs.execute('select * from user_user')
print(curosrs.fetchall())
#添加修改添加以及删除数据无需二次确认

image

image

神奇的双下划线查询

只要还是Query Set对象就可以无限制的点Query Set对象的方法

返回是Query Set对象的ORM常用方法

filter()	    # 筛选数据
all()			# 查询所有数据
reverse()   	# 颠倒,必须排序之后才能使用否则不生效
order_by()  	# 对Query Set里面对象按照指定字段排序
exclude()		# 查询除了当前数据的其他数据
values()	    # 查询所有数据的指定字段的值,为列表套字典
values_list()	# 查询所有数据的指定字段的值,为列表套元组
distinct()		# 去重数据必须一模一样,如果带主键那么数据肯定不一样,无法去重

__gt大于

# 查询年龄大于18的用户数据
res = models.User.objects.filter(age__gt=18) # gt大于
print(res)

image

__lt小于

# 查询年龄小于38的用户数据
res = models.User.objects.filter(age__lt=38)
print(res)

image

__gte大于等于,__lte小于等于

# 查询年龄大于等于18的用户数据
# 查询年龄小于等于18的用户数据
res = models.User.objects.filter(age__gte=18)
print(res)
res= models.User.objects.filter(age__lte=38)
print(res)

image

__in在这个数据集里面

# 查询年龄是18或者28或者38的数据
res = models.User.objects.filter(age__in=(18,28,38))
print(res)

image

__range查询范围内的数据

res = models.User.objects.filter(age__range=(18,38))
print(res)

image

__contains匹配字符区分大小写
__icontains 匹配字符不区分大小写

res = models.User.objects.filter(name__contains='j')
    print(res)  # 区分大小写
    res = models.User.objects.filter(name__icontains='J')
    print(res)  # 不区分大小写

image

__year__month··· 根据时间查

不修改失去,根据日期查询,无法查询到数据

res = models.User.objects.filter(register_time__year=2000)
print(res)
res = models.User.objects.filter(register_time__day=6)
print(res)

image

settings.py配置文件修改

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

修改完毕之后正常查询数据

res = models.User.objects.filter(register_time__year=2000)
print(res)
res = models.User.objects.filter(register_time__day=6)
print(res)
res = models.User.objects.filter(register_time__month=6)
print(res)

image

ORM外键字段的创建

复习MySql外键关系

一对多:外键建在多的一方

多对多:外键需要建在第三张关系表中

一对一:建在任何一方都可以,但是推荐外键建在查询频率较高的一方

外键关系的判断:使用换位思考原则

准备数据

  1. 创建基础表(书籍表,出版社表,作者表,作者详情表)

  2. 确定外键关系
    一对多 ORM与MySql一致建在多的一方
    多对多 ORM比MySQL有更多变化

    1. 外键字段可以直接建在某张表中(查询频率较高的)
      内部会自动帮我们创建第三张表
    2. 自己创建第三表关系并创建外键字段
      暂时忽略

    一对一 ORM与MySQL一致 外键建在查询频率较高的一方

  3. 在djngo1.x版中默认是级联更新级联删除的,而django2.x以上版默认不是级联更新级联删除的,而如果我们不加的话默认是会报错的
    image

    在多对多外键字段中不能添加级联更新级联删除
    image

  4. ORM创建
    针对一对多和一对一与同步到表中之后会字段会自动加_id的后缀。

    一对多
    # 书籍表与出版社表外键关系
    # 一本书只能对应一个出版社,而一个出版社可以对应很多本书书,
    # 所以书籍表对出版社表是多对一的关系,建在多的一方,也就是书籍表
    publish = models.ForeignKey(to='Publsh', on_delete=models.CASCADE)
    # 在djngo1.x版中默认是级联更新级联删除的,
    # 而django2.x以上版默认不是级联更新级联删除的,而如果我们不加的话默认是会报错的
        
    一对一  
    # 作者表与作者详情表外键关系
    # 一个作者只能有一个详细信息,而一个详细信息只能有个作者所以是一对一的关系
    # 又因为作者表查询频率比较高,所以外键字段建在查询频率较高的一方也就是作者表
    authorDetail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)
    
    

    针对多对对 不会在表中有展示 而是创建第三张表

    多对多
    # 书籍表与作者表外键关系
    # 一本书可以有多个作者,而一个作者可以写多本书
    # 所以书籍表与作者表的关系就是多对多,
    # 然后,数据表查询频率比作者表查询频率高,所以在ORM中外键字段建在书籍表中
    author = models.ManyToManyField(to='Author')
    

    image

外键字段相关操作

在没有外键表中插入数据

插入出版社数据

odels.Publsh.objects.create(name='北方出版社',address='北方')
models.Publsh.objects.create(name='南方出版社',address='南方')
models.Publsh.objects.create(name='东方出版社',address='东方')
models.Publsh.objects.create(name='西方出版社',address='西方')

image

插入作者详情表数据

models.AuthorDetail.objects.create(phone=18888888888, address='北京')
    models.AuthorDetail.objects.create(phone=17777777777, address='南京')
    models.AuthorDetail.objects.create(phone=16666666666, address='上海')
    models.AuthorDetail.objects.create(phone=18899999999, address='厦门')

针对一对多 插入数据可以直接填写表中的实际字段

# 针对一对多 插入数据可以直接填写表中的实际字段
book_obj = models.Book.objects.create(title='水浒传', price=888.11, publish_id=1)  
# 直接添加数据需要指定表中的字段,外键字段会自动加_id所以在添加的时候字段名字为publish_id=1
print(book_obj)
book_obj = models.Book.objects.create(title='三国演义', price=666.88, publish_id=1)
print(book_obj)
book_obj = models.Book.objects.create(title='斗罗大陆', price=8888.88, publish_id=2)
print(book_obj)
book_obj = models.Book.objects.create(title='斗破苍穹', price=6666.66, publish_id=3)
print(book_obj)
book_obj = models.Book.objects.create(title='三体', price=555.89, publish_id=4)
print(book_obj)
#


# 针对一对多 插入数据也可以填写表中的类中字段名
publish_obj = models.Publsh.objects.filter(pk=1).first()
models.Book.objects.create(title='金瓶', price=99999.99, publish=publish_obj)  
## 使用对象进行数据插入要使用类中的字段名进行添加


# 书籍对象:水浒传
# 书籍对象:三国演义
# 书籍对象:斗罗大陆
# 书籍对象:斗破苍穹
# 书籍对象:三体
# 书籍对象:金瓶

针对一对一与一对多一致,既可以传数字也可以传对象

models.Author.objects.create(name='jason', age=18, authorDetail_id=1)
# 直接添加数据需要指定表中的字段,外键字段会自动加_id所以在添加的时候字段名字为authorDetail_id=1
models.Author.objects.create(name='tom', age=28, authorDetail_id=2)
models.Author.objects.create(name='张三', age=58, authorDetail_id=4)
authordetail_obj = models.AuthorDetail.objects.filter(pk=3).first()
models.Author.objects.create(name='kunkun', age=38, authorDetail=authordetail_obj)
## 使用对象进行数据插入要使用类中的字段名authorDetail进行添加

## 一对一数据修改
author_qeury.update(name=name,age=age)
aud = author_qeury.first().authorDetail
aud.addr=addr
aud.phone=phone
aud.email=email
aud.save()


针对多对多关系绑定

# 增加数据
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.add(1)
book_obj.authors.add(4,3)

book_obj = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj1, author_obj2)

# 修改数据
book_obj = models.Book.objects.filter(pk=4).first()
book_obj.authors.set((1, 3))

book_obj = models.Book.objects.filter(pk=4).first()
author_obj = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj, ])

# 删除数据
book_obj = models.Book.objects.filter(pk=3).first()
# book_obj.authors.remove(3)
# 与下面同理
author_obj = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
# 清空当前数据对象的关系
bokk_obj.authors.clear()

add()/remove()    多个位置参数(数字,对象)
set()			  可迭代对象(元组 列表)数字 对象
clear()			  清空当前数据对象的关系

ORM跨表查询

复习MySql 跨表查询的思路

子查询 分步操作:将一条Sql语句当作另一条SQL语句查询条件

连表操作:先整合多张表之后基于单表查询即可

inner join  内连接 基于两个表中共有的数据字段展示
left  join	左连接 以左表为基准展示数据
right join	右连接 以右表为基准展示数据

正反向查询的概念(重要)

正向查询
由外键字段所在的表数据查询为关联表的表数据 正向
反向查询
没有外键字段的表数据查询关联的表数据 反向

正反向的核心就看外键字段在不在当前数据所在的表中

ORM跨表查询的口诀(重要)

正向查询按外键字段

反向查询按表名小写

基于对象的跨表查询

1.查询主键为1的书籍对应的出版社名称(正向查询)

book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish.name)

image-20221215214837225

2.查询主键为4的书籍对应的作者姓名(正向查询)

book_obj = models.Book.objects.filter(pk=3).first()
print(book_obj.authors)  # User.Author.None 是多对多字段,看见这个不要慌,里正确步骤就只差一步,
print(book_obj.authors.all())  #就把所以数据拿出来 <QuerySet [<Author: 作者对象:tom>]>

image

3.查询jason的电话号码(正向查询)

# 先查出jason对象。因为外键字段在当前表,所是正向查询
author_obj = models.Author.objects.filter(name='jason').first()
# 因为是一对一字段,用对象点外键字段可以直接获取数据
print(author_obj.authorDetail.phone)

image

4.查询北方出版社出版过的书籍(反向查询)

publish_obj = models.Publsh.objects.filter(name='北方出版社').first()
# 外键字段不在当前表,所是反向查询
# 反向查询是对象点类名小写,出版社是一对多关系所以用boot_set
print(publish_obj.book_set)
print(publish_obj.book_set.all())

image

5.查询jason写过的书籍(反向查询)

author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.book_set)
print(author_obj.book_set.all().values('title'))

image-20221215220708398

6.查询电话号码是18888888888的作者姓名(反向查询)

authordetail = models.AuthorDetail.objects.filter(phone=18888888888).first()
# 一对一 结果是精准的类名不用加_set
print(authordetail.author.name)

image

总结

如果用结果对象,无论是正向还是反向,如果站在当前对象表对应跨到的查询表,当前对象可能有多个结果数据的情况下那么需要使用all()方法来取数据不能直接点类表中的字段拿数据,否则就可以使用点类表中的字段形式获取数据

基于双下划线的跨表查询

1.查询主键为1的书籍对应的出版社名称(正向查询)

 # 1.查询主键为1的书籍对应的出版社名称
    # 先查询到主键为1的书籍,正向查询,直接点values('外键字段__要查询的关联表中的字段','因为手中本来就是书籍表所以可以直接查询当前表中的字段')
    res = models.Book.objects.filter(pk=1).values('publish__name','title')
    print(res)

image

2.查询主键为1的书籍对应的作者姓名(正向查询)


res = models.Book.objects.filter(pk=1).values('authors__name','title')
print(res)

image

3.查询jason的电话号码(正向查询)

res = models.Author.objects.filter(name='jason').values('authorDetail__phone','name')
print(res)

image

4.查询北方出版社出版过的书籍(反向查询)

res = models.Publsh.objects.filter(name='北方出版社').values('book__title')
print(res)

image

5.查询jason写过的书籍(反向查询)

res = models.Author.objects.filter(name='jason').values('book__title')
print(res)

image-20221215223243293

6.查询电话号码是18888888888的作者姓名(反向查询)

res = models.AuthorDetail.objects.filter(phone=18888888888).values('author__name')
print(res)

image-20221215223345043

进阶查询

1.查询主键为1的书籍对应的出版社名称

# 用后面的表对前面条件进行过滤,然后再直接拿后面表要拿的数据  
    res = models.Publsh.objects.filter(book__id=1).values('name')
    print(res)

image

2.查询主键为3的书籍对应的作者姓名

res=  models.Author.objects.filter(book__pk=3).values('name')
print(res)

image

3.查询jason的电话号码

res=  models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res)

image

4.查询北方出版社出版过的书籍

res=  models.Book.objects.filter(publish__name='北方出版社').values('title')
    print(res)

image

5.查询jason写过的书籍

res = models.Book.objects.filter(authors__name='jason').values('title')
print(res)

image

6.查询电话号码是18888888888的作者姓名

res = models.Author.objects.filter(authorDetail__phone=18888888888).values('name')
print(res)

image

补充(各种姿势查)

查询主键为3的书籍对应的作者的电话号码(第一张表为开头)

res = models.Book.objects.filter(pk=3).values('authors__authorDetail__phone')
    print(res)

image

查询主键为3的书籍对应的作者的电话号码(第二张表为开头)

res = models.Author.objects.filter(book__pk=3).values('authorDetail__phone')
print(res)

image

查询主键为3的书籍对应的作者的电话号码(第三张表为开头)

#从哪个表开始从哪跨表,必须连续跳,不能隔表跳

res = models.AuthorDetail.objects.filter(author__book__pk=3).values('phone')
print(res)

image

补充总结

从哪个表开始从哪跨表,必须连续跳,不能隔表跳

获取每个组的最新信息

再有外键的表先用外键跨到需要用到的表,然后再用表名跨回来有外键的表进行分组,条件查询,最后进行过滤

# 获取每个站点用户的最新发布的文章

user_query=models.Article.objects.annotate(max_pk=Max('site__article__pk')).filter(pk=F('max_pk'))
print(user_query)
print(len(user_query))

聚合查询

常见聚合函数

max 取最大值

min 取最小值

count 统计总数

sum 求和

avg 求平均值

再ORM中支持单独使用聚合函数 aggregate

# 要先到导入模块才能使用
from django.db.models import Max, Min, Sum, Count, Avg
res = models.Book.objects.aggregate(最大价格=Max('price'), 最小主键=Min('pk'), total_price=Sum('price'),
                                    total_num=Count('pk'), 平均值=Avg('price'))
print(res)

image

分组查询

分组查询关键字annotate

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

res = models.Publsh.objects.annotate(Count('name'))
print(res)

image

修改数据的sql_mode把only-full-group_by去掉

image

修改后就能正常查询了

image

统计每一本书的作者个数

# 首先以Book书为分组,外键再手中,是正向查询
# 然后再用Count统计外键字段authors人数
# 最后再用values拿出统计的人数
res = models.Book.objects.annotate(aut_num =Count('authors')).values('title','aut_num')
print(res)

image

统计出每个出版社卖的最便宜的书的价格

#只有对象才会查询才会用到_set
res = models.Publsh.objects.annotate(price_num=Min('book__price')).values('name','price_num')
print(res)

image

统计不止一个作者的图书

# 首先根据书籍分组,统计各个图书作者个数,
# 然后过滤作者大于1的图书
# 拿出图书名称
res = models.Book.objects.annotate(aut_num=Count('authors')).filter(aut_num__gt=1).values('title','aut_num')
print(res)

image

查询每个作者出的书的总价格

res = models.Author.objects.annotate(aut_num=Count('book__pk'), sum_num=Sum('book__price')).values('aut_num', 'sum_num','name')
print(res)

image

models.表名.objects.annotate()  # 按照表分组
models.表名.objects.values('字段名').annotate() # 按照values括号内的指定的字段分组


#查询每个作者出的书的总价格按字段分组,查询
res = models.Author.objects.values('pk').annotate(aut_num=Count('book__pk'),sum_num=Sum('book__price')).values('aut_num','sum_num','name')
print(res)


F与Q查询

1.查询库存数大于卖出数的书籍

from django.db.models import F
res = models.Book.objects.filter(kucun__gt=F('sale'))
print(res)

image

2.将所有书的价格涨800

from django.db.models import F
res = models.Book.objects.update(price=F('price')+800)
print(res)

image

3.将所有书的名称后面追加爆款

from django.db.models import F, Value
from django.db.models.functions import Concat
res = models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
print(res)

image

4.查询主键是1或者价格大于2000的书籍

# 查询主键是1或者价格大于2000的书籍
from django.db.models import F, Q, Value  # 与或非条件的时使用Q查询
from django.db.models.functions import Concat

res = models.Book.objects.filter(Q(pk=1) | Q(price__gt=2000))
print(res)

# 查询主键不是1或者价格不大于2000的书籍  # ~是not   &是and  |是or
res = models.Book.objects.filter(~Q(pk=1) | ~Q(price__gt=2000))
print(res)

image

总结F查询与Q查询

F查询针对与,需要再原有基础上做数据更改而使用的

Q查询针对与,再过条件中需要使用& and 与,| or 或,~ not 非 使用的

Concat 是在F查询字符串拼接的时候使用

posted @ 2022-12-14 22:57  clever-cat  阅读(109)  评论(0编辑  收藏  举报