• Django——模型层进阶


    一对多外键增删改

    1. 两种设置外键字段的方式

    1. '''
    2. 2种设置外键字段的方式
    3. 1. 实际字段指定id publish_id=id
    4. 2. 虚拟字段指定对象 publish=publish_obj
    5. '''

    2. 增 create

    1. models.Book.objects.create(title='论语', price='333.33', publish_id=1)
    2. models.Book.objects.create(title='孟子', price='444.44', publish_id=2)
    3. models.Book.objects.create(title='老子', price='555.55', publish_id=2)
    4. publish_obj = models.Publish.objects.filter(pk=1).first()
    5. models.Book.objects.create(title='三字经', price='666.66', publish=publish_obj)

    3. 删 delete

    models.Book.objects.filter(pk=1).delete()  # 级联删除

    4. 改 update

    1. models.Book.objects.filter(pk=2).update(publish_id=1)
    2. publish_obj = models.Publish.objects.filter(pk=2).first()
    3. models.Book.objects.filter(pk=2).update(publish=publish_obj)

    5. 总结

    1. # 增 create
    2. # 实际
    3. models.Book.objects.create(publish_id=id, **kwargs)
    4. # 虚拟
    5. publish_obj = models.Publish.objects.filter(pk=1).first()
    6. models.Book.objects.create(publish=publish_obj, **kwargs)
    7. # 删 delete
    8. models.Book.objects.filter(pk=1).delete() # 级联删除
    9. # 改 update
    10. # 实际
    11. models.Book.objects.filter(pk=1).update(publish_id=id)
    12. # 虚拟
    13. publish_obj = models.Publish.objects.filter(pk=1).first()
    14. models.Book.objects.filter(pk=1).update(publish=publish_obj)
    15. # 查
    16. # 实际
    17. # 虚拟

    多对多外键增删改: 本质就是操作虚拟中间表(第三种表)

    1. 增 add

    1. '''
    2. add给第三张关系表添加数据
    3. 括号内既可以传数字也可以传对象 并且都支持多个
    4. '''
    5. book_obj = models.Book.objects.filter(pk=3).first()
    6. # print(book_obj.authors) # app01.Author.None(就类似于你已经到了第三张关系表了)
    7. # book_obj.authors.add(1) # 添加一个book_id是3对应的author_id是1的记录
    8. # book_obj.authors.add(2, 3)
    9. book_obj = models.Book.objects.filter(pk=3).first()
    10. authors1 = models.Author.objects.filter(pk=1).first()
    11. authors2 = models.Author.objects.filter(pk=2).first()
    12. authors3 = models.Author.objects.filter(pk=3).first()
    13. book_obj.authors.add(authors1)
    14. book_obj.authors.add(authors2, authors3)

    2. 删 remove

    1. '''
    2. 括号内既可以传数字也可以传对象 并且都支持多个
    3. '''
    4. book_obj = models.Book.objects.filter(pk=2).first()
    5. book_obj.authors.remove(1) # 删除虚拟表中book_id是2的对应的author_id是1的记录
    6. book_obj.authors.remove(2, 3)

    3. 改 set

    1. '''
    2. 括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个
    3. 注意!!!: set操作是一种新增操作. 执行set一上来先将括号内没有指定的全部清除, 如果有则保留, 没有则新增. 如果想修改某一个数据, 必须对源数据进行指定, 不然源数据将会被清除.
    4. '''
    5. book_obj = models.Book.objects.filter(pk=3).first()
    6. book_obj.authors.set([1, 2]) # 先删除author_id不是等于1,2的, 如果没有1, 2则添加
    7. book_obj = models.Book.objects.filter(pk=3).first()
    8. authors1 = models.Author.objects.filter(pk=1).first()
    9. authors2 = models.Author.objects.filter(pk=2).first()
    10. book_obj.authors.set([authors1, authors2])

    4. 清空 clear

    1. '''
    2. 括号内不要加任何参数
    3. '''
    4. book_obj = models.Book.objects.filter(pk=3).first()
    5. book_obj.authors.clear() # 清空book_id为3所对应的所有author_id

    5. 总结

    1. # 增 add 可以指定多个
    2. # 提示: .authors时已经到第三张表了
    3. # 实际
    4. models.Book.objects.filter(pk=1).first().authors.add(1, 2)
    5. # 虚拟
    6. author = models.Author.objects.filter(pk=1).first()
    7. models.Book.objects.filter(pk=1).first().authors.add(author)
    8. # 删 remove 可以指定多个
    9. # 提示: .authors时已经到第三张表了
    10. # 实际
    11. models.Book.objects.filter(pk=1).first().authors.remove(1, 2)
    12. # 虚拟
    13. author = models.Author.objects.filter(pk=1).first()
    14. models.Book.objects.filter(pk=1).first().authors.remove(author)
    15. # 改 set 放可迭代对象, 可迭代对象中可指定多个
    16. # 注意: 是一种新增操作. 执行set一上来先将括号内没有指定的全部清除, 如果有则保留, 没有则新增. 如果想修改某一个数据, 必须对源数据进行指定, 不然源数据将会被清除.
    17. # 实际
    18. models.Book.objects.filter(pk=1).first().authors.set([1, 2])
    19. # 虚拟
    20. author = models.Author.objects.filter(pk=1).first()
    21. models.Book.objects.filter(pk=1).first().authors.set([author])
    22. # 清空 clear
    23. models.Book.objects.filter(pk=1).first().authors.clear()

    查询前必须要搞清楚的一件事

    1. # 正向查询
    2. 正向查询按字段.
    3. 正向: 外键字段在的一方查不在的一方
    4. 如果返回结果多个还需要.all()
    5. # 反向查询
    6. 反向查询按表名小写.
    7. 反向: 外键字段不在的一方查在的一方
    8. 如果返回结果多个还需要连接_set.all()
    9. # 提示:
    10. 书籍与作者, 外键字段在书籍.
    11. 作者与作者详情, 外键字段在作者.
    12. 书籍与出版社外键字段在书籍.

    子查询: 基于对象的跨表查询

    1. 正向查询

    1. '''
    2. 正向查询按字段
    3. 当你的结果可能有多个的情况下就需要加.all()
    4. book_obj.authors.all()
    5. 如果是一个则直接拿到数据对象
    6. book_obj.publish
    7. author_obj.author_detail
    8. '''
    9. # 1. 查询书籍主键为1的出版社
    10. book_obj = models.Book.objects.filter(pk=1).first()
    11. print(book_obj.publish.name) # 北方出版社
    12. # 2. 查询书籍主键为2的作者: 一本书可能被多个作者出版使用.all()
    13. book_obj = models.Book.objects.filter(pk=2).first()
    14. print(book_obj.authors) # app01.Author.None
    15. print(book_obj.authors.all()) # , ]>
    16. # 3. 查询作者jason的电话号码:
    17. author_obj = models.Author.objects.filter(name='jason').first()
    18. print(author_obj.author_detail) # AuthorDetail object
    19. print(author_obj.author_detail.phone) # 110

    2. 反向查询

    1. '''
    2. 反向查询按表名小写
    3. 如果查询结果可以有多个就必须需要加_set.all()
    4. publish_obj.book_set.all()
    5. author_obj.book_set.all()
    6. 如果查询结果只有一个的时候就不需要加_set.all()
    7. author_detail_obj.author
    8. '''
    9. # 4. 查询出版社是东方出版社出版的书: 一个出版社可以出版多本书使用.all()
    10. publish_obj = models.Publish.objects.filter(name='东方出版社').first()
    11. print(publish_obj.book_set) # app01.Book.None
    12. print(publish_obj.book_set.all()) # , ]>
    13. # 5. 查询作者是jason写过的书: 一个作者jason可以写过多本书
    14. author_obj = models.Author.objects.filter(name='jason').first()
    15. print(author_obj.book_set) # app01.Book.None
    16. print(author_obj.book_set.all()) # ]>
    17. # 6. 查询手机号是110的作者姓名
    18. author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
    19. print(author_detail_obj.author.name) # jason

    3. 总结

    1. '''子查询: 基于对象的跨表查询'''
    2. # 正向: 查询书籍主键为1的出版社
    3. models.Book.objects.filter(pk=1).first().publish.name
    4. # 正向: 查询书籍主键为2的作者
    5. models.Book.objects.filter(pk=2).first().authors.all()
    6. # 正向: 查询作者jason的电话号码
    7. models.Author.objects.filter(name='jason').first().author_detail.phone
    8. # 反向: 查询出版社是东方出版社出版的书
    9. models.Publish.objects.filter(name='东方出版社').first().publish_set.all()
    10. # 反向: 查询作者是jason写过的书
    11. models.Author.objects.filter(name='jason').first().book_set.all()
    12. # 反向: 查询手机号是110的作者姓名
    13. models.AuthorDetail.objects.filter(phone=110).first().author.name

    连表查询: 基于双下划线的连表查询

    1. '''连表查询: 基于双下划线的连表查询'''
    2. # 查询jason的手机号和作者姓名
    3. # 正向
    4. models.Author.objects.filter(name='jason').values('author_detail__phone', 'name')
    5. # 反向
    6. models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__name')
    7. # 查询书籍主键为1的出版社名称和书的名称
    8. # 正向
    9. models.Book.objects.filter(pk=1).values('publish__name', 'title')
    10. # 反向
    11. models.Publish.objects.filter(book__pk=1).values('name' 'book__title')
    12. # 查询书籍主键为1的作者姓名
    13. # 正向
    14. models.Book.objects.filter(pk=1).values('authors__name')
    15. # 反向
    16. models.Author.objects.filter(book_pk=1).values('name')
    17. # 查询书籍主键是1的作者的手机号
    18. # 正向
    19. models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    20. # 反向
    21. models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')

     

    总结

    1. # 配置测试脚本
    2. manage.py中3行语句. 再写入如下内容:
    3. import django
    4. django.setup()
    5. # 单表操作: 数据的增删改查
    6. # 提示: 使用pk标识主键
    7. # 增
    8. # 第一种方式: 自动保存
    9. models.User.objects.create(**kwargs).
    10. # 第二种方式: 手动.save()保存
    11. models.User(**kwargs).save()
    12. # 删
    13. # 第一种方式: 统一的删除
    14. models.User.objects.filter(**Kwargs).delete()
    15. # 第二种方式: 单一的删除
    16. models.User.objects.filter(**Kwargs).first().delete()
    17. # 改
    18. # 第一种方式: 统一的更新
    19. models.User.objects.filter(**Kwargs).update(**kwargs)
    20. # 第二种方式: 单一的更新
    21. user_obj = models.User.objects.filter(**Kwargs).first()
    22. user_obj.username = 'jason'
    23. user_obj.save()
    24. # 查
    25. # 第一种方式: 获取所有.
    26. models.User.objects.filter()
    27. models.User.objects.all()
    28. # 第二种方式: 获取单个对象
    29. user_queryset = models.User.objects.filter(**kwargs)
    30. user_obj = user_queryset.first()
    31. user_obj = user_queryset.last()
    32. models.User.objects.get()
    33. # 注意:
    34. # 返回QuerySet对象. 没有值返回空的QuerySet对象
    35. .filter()
    36. .all()
    37. # 获取单个数据对象.
    38. QuerySet.first() 在QuerySet为空的情况下返回None
    39. QuerySet.last() 在QuerySet为空的情况下返回None
    40. .get() 指定的条件的返回结果有多个或者不存在抛出异常(不推荐使用)
    41. # 必知必会13条
    42. # 返回QuerySet对象的方法
    43. .all() 获取所有.
    44. .filter() 过滤. 不指定参数获取所有. 查询结果不存在返回空的QuerySet对象, 布尔值False
    45. .distinct() 去重. 必须排除主键字段 或 唯一字段才会有意义. filter无法筛选, 一般用在.values() 或 .value_list()后面
    46. .order_by() 排序. 默认升序. 指定降序在字段前加`-`
    47. .reverse() 反转. 只能对排序过后进行反转. 必须在.order_by()之后.
    48. .exclude() 排除. 排除指定的, 展示所有.
    49. # 返回特殊QuerySet对象的方法
    50. .values() 返回QuerySet之内部列表套字典格式. 字典key就是指定的字段.
    51. .values_list() 返回QuerySet之内部列表套元组格式. 元组中值就是指定字段对应的值, 按照指定字段顺序显示.
    52. 注意!!!: 指定的字段不存在, 将会抛出异常
    53. # 返回数据对象的方法
    54. .get() 直接获取数据对象. 只能指定一个筛选条件. 如果指定的筛选条件返回的结果不唯一 或者 不存在 抛出异常
    55. .first() 获取QuerySet对象列表内第一个值. 用在QuerySet对象之后, 如果QuerySet对象为空, 再使用它返回None
    56. .last() 获取QuerySet对象列表内最后一个值. 用在QuerySet对象之后, 如果QuerySet对象为空, 再使用它返回None
    57. # 返回数字的方法
    58. .count() 统计QuerySet对象列表内数据对象的个数
    59. # 返回布尔值的方法
    60. .exist() 没软用
    61. # 查看内部封装的sql语句的2种形式
    62. 第一种: QuerySet.query
    63. 第二种: 执行脚本时打印日志显示到终端. 复制日志内容到settings.py中
    64. # 神奇的双下划线查询
    65. # 注意: 争对字段使用. 如: field__gt
    66. __gt __lt __gte __glt
    67. __in=[] __range=[start, stop]
    68. __contains __icontains i全称忽略ignore
    69. __startswith __istartswith
    70. __endswith __iendswith
    71. __year='2020' __year=2020
    72. __month='1' __month=1
    73. __day='20' __day=20
    74. # 2种外键字段指定的方式
    75. 第一种: 实际字段指定id publish_id=id
    76. 第二种: 虚拟字段指定对象 publish=publish_obj
    77. # 一对多外键增删改查
    78. # 增 create
    79. # 实际
    80. models.Book.objects.create(publish_id=id, **kwargs)
    81. # 虚拟
    82. publish_obj = models.Publish.objects.filter(pk=1).first()
    83. models.Book.objects.create(publish=publish_obj, **kwargs)
    84. # 删 delete
    85. models.Book.objects.filter(pk=1).delete() # 级联删除
    86. # 改 update
    87. # 实际
    88. models.Book.objects.filter(pk=1).update(publish_id=id)
    89. # 虚拟
    90. publish_obj = models.Publish.objects.filter(pk=1).first()
    91. models.Book.objects.filter(pk=1).update(publish=publish_obj)
    92. # 查
    93. # 实际
    94. # 虚拟
    95. # 多对多外键增删改查: 本质就是操作虚拟中间表(第三种表)
    96. # 增 add 可以指定多个
    97. # 提示: .authors时已经到第三张表了
    98. # 实际
    99. models.Book.objects.filter(pk=1).first().authors.add(1, 2)
    100. # 虚拟
    101. author = models.Author.objects.filter(pk=1).first()
    102. models.Book.objects.filter(pk=1).first().authors.add(author)
    103. # 删 remove 可以指定多个
    104. # 提示: .authors时已经到第三张表了
    105. # 实际
    106. models.Book.objects.filter(pk=1).first().authors.remove(1, 2)
    107. # 虚拟
    108. author = models.Author.objects.filter(pk=1).first()
    109. models.Book.objects.filter(pk=1).first().authors.remove(author)
    110. # 改 set 放可迭代对象, 可迭代对象中可指定多个
    111. # 注意: 是一种新增操作. 执行set一上来先将括号内没有指定的全部清除, 如果有则保留, 没有则新增. 如果想修改某一个数据, 必须对源数据进行指定, 不然源数据将会被清除.
    112. # 实际
    113. models.Book.objects.filter(pk=1).first().authors.set([1, 2])
    114. # 虚拟
    115. author = models.Author.objects.filter(pk=1).first()
    116. models.Book.objects.filter(pk=1).first().authors.set([author])
    117. # 清空 clear
    118. models.Book.objects.filter(pk=1).first().authors.clear()
    119. # 查询语法
    120. # 正向查询
    121. 正向查询按字段.
    122. 正向: 外键字段在的一方查不在的一方
    123. 如果返回结果多个还需要.all()
    124. # 反向查询
    125. 反向查询按表名小写.
    126. 反向: 外键字段不在的一方查在的一方
    127. 如果返回结果多个还需要连接_set.all()
    128. # 提示:
    129. 书籍与作者, 外键字段在书籍.
    130. 作者与作者详情, 外键字段在作者.
    131. 书籍与出版社外键字段在书籍.
    132. # 子查询: 基于对象的跨表查询
    133. # 正向: 查询书籍主键为1的出版社
    134. models.Book.objects.filter(pk=1).first().publish.name
    135. # 正向: 查询书籍主键为2的作者
    136. models.Book.objects.filter(pk=2).first().authors.all()
    137. # 正向: 查询作者jason的电话号码
    138. models.Author.objects.filter(name='jason').first().author_detail.phone
    139. # 反向: 查询出版社是东方出版社出版的书
    140. models.Publish.objects.filter(name='东方出版社').first().publish_set.all()
    141. # 反向: 查询作者是jason写过的书
    142. models.Author.objects.filter(name='jason').first().book_set.all()
    143. # 反向: 查询手机号是110的作者姓名
    144. models.AuthorDetail.objects.filter(phone=110).first().author.name
    145. # 连表查询: 基于双下划线的连表查询
    146. # 查询jason的手机号和作者姓名
    147. # 正向
    148. models.Author.objects.filter(name='jason').values('author_detail__phone', 'name')
    149. # 反向
    150. models.AuthorDetail.objects.filter(author__name='jason').values('phone', 'author__name')
    151. # 查询书籍主键为1的出版社名称和书的名称
    152. # 正向
    153. models.Book.objects.filter(pk=1).values('publish__name', 'title')
    154. # 反向
    155. models.Publish.objects.filter(book__pk=1).values('name' 'book__title')
    156. # 查询书籍主键为1的作者姓名
    157. # 正向
    158. models.Book.objects.filter(pk=1).values('authors__name')
    159. # 反向
    160. models.Author.objects.filter(book_pk=1).values('name')
    161. # 查询书籍主键是1的作者的手机号
    162. # 正向
    163. models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
    164. # 反向
    165. models.AuthorDetail.objects.filter(author__book__pk=1).values('phone')

    聚合查询 aggregate

    1. """
    2. 介绍: 聚合查询通常情况下都是配合分组一起使用的. 如果你只想使用聚合函数, 但是不想分组, 那么就应该使用aggregate.
    3. 使用: 直接在objects后面链接.
    4. 返回: 返回字典格式的数据. 如果是对price字段求平均值, 那么返回格式是: {'price__avg': 值}
    5. 记忆跟数据库相关的模块的方法:
    6. 基本上都在django.db.models里面
    7. 如果上述没有那么应该在django.db里面
    8. """
    9. from django.db.models import Max, Min, Sum, Avg, Count
    10. # 1. 所有书的平均价格
    11. res = models.Book.objects.aggregate(Avg('price'))
    12. print(res) # {'price__avg': 555.55}
    13. # 2. 上述方法一次性使用
    14. res = models.Book.objects.aggregate(Max('price'), Min('price'), Sum('price'), Avg('price'), Count('pk'))
    15. print(res) # {'price__max': Decimal('888.88'), 'price__min': Decimal('333.33'), 'price__sum': Decimal('3888.85'), 'price__avg': 555.55, 'pk__count': 7}

    分组查询 annotate

    1. 介绍

    1. """
    2. 分组注意事项: 分组只能拿到分组得依据. 按照什么分组就只能拿到什么组. 其他字段不能直接获取, 需要借助一些方法(聚合函数)
    3. 提示: 可以指定多个分组, 指定多个分组, 当然就可以获取多个分组之间的分组依据.
    4. MySQl中设置全局生效得分组严格模式: set global sql_mode='only_full_group_by';
    5. 使用步骤:
    6. 第一步: 指定分组的依据
    7. 第一种情况: 默认分组. annotate直接在objects后面链接时, models后面点什么就按照什么分组.
    8. 例子: 按照书分组
    9. models.Book.objects.annotate(sum_price=Sum)
    10. 第二种情况: 指定分组. annotate跟在values后面, values中指定什么字段就按照什么分组
    11. 例子: 按照书中的价格分组.
    12. models.Book.objects.values('price').annotate()
    13. 第二步: 为分组的字段取别名
    14. 第三步: 在annotate后面使用values可以获取分组的依据 和 分组举和的结果
    15. 返回: 返回QuerySet对象
    16. 提示: 只要你的orm语句得出的结果还是一个queryset对象, 那么它就可以继续无限制的点queryset对象封装的方法.
    17. 特殊情况使用: 使用Count进行获取分组举和的结果应该是要对主键 或者 唯一字段进行的统计. 所以使用Count进行统计时比如: authors__id 就可以写成 authors
    18. """

    2. 统计每一本书的作者个数

    1. """
    2. 原生SQL语句: !!!注意!!! 可能作者没有写过书.
    3. select book_id, count(author_id) from app01_book_authors group by book_id;
    4. select app01_book.title,t1.author_count from
    5. app01_book
    6. left join
    7. (select book_id, count(author_id) as author_count from app01_book_authors group by book_id) as t1
    8. on t1.book_id=app01_book.id;
    9. """
    10. # res = models.Book.objects.annotate(book_count=Count('authors__id')).values('title', 'book_count')
    11. res = models.Book.objects.annotate(book_count=Count('authors')).values('title', 'book_count')
    12. print(res) #

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

    1. """
    2. 原生SQL语句:
    3. select publish_id, title, min(price) from app01_book group by publish_id;
    4. select app01_publish.name, t1.* from
    5. app01_publish
    6. inner join
    7. (select publish_id, title, min(price) from app01_book group by publish_id) as t1
    8. on app01_publish.id=t1.publish_id;
    9. """
    10. res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')
    11. print(res) #

    4. 统计不止一个作者的图书

    1. """
    2. 第一步: 对书分组, 求作者的个数
    3. 第二步: 过滤出作者个数大于1的.
    4. 原生SQL语句:
    5. select book_id, count(author_id) from app01_book_authors group by book_id having count(author_id)>1;
    6. select app01_book.title, t1.author_count
    7. from app01_book
    8. inner join
    9. (select book_id, count(author_id) as author_count from app01_book_authors group by book_id having count(author_id)>1) as t1
    10. on t1.book_id=app01_book.id;
    11. """
    12. res = models.Book.objects.annotate(author_count=Count('authors')).filter(author_count__gt=1).values('title', 'author_count')
    13. print(res) #

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

    1. """
    2. 原生SQL语句:
    3. select app01_book_authors.author_id, sum(app01_book.price)
    4. from app01_book
    5. inner join
    6. app01_book_authors
    7. on app01_book_authors.book_id=app01_book.id
    8. group by app01_book_authors.author_id;
    9. select app01_author.name, t2.sum_price
    10. from app01_author
    11. inner join
    12. (select app01_book_authors.author_id as author_id, sum(app01_book.price) as sum_price
    13. from app01_book
    14. inner join
    15. app01_book_authors
    16. on app01_book_authors.book_id=app01_book.id
    17. group by app01_book_authors.author_id) as t2
    18. on t2.author_id=app01_author.id;
    19. """
    20. res = models.Author.objects.annotate(price_sum=Sum('book__price')).values('name', 'price_sum')
    21. print(res) #
    22. '''

     

    总结

    1. # 聚合查询 aggregate
    2. # 作用: 在不分组的前提下也能使用聚合函数
    3. # 使用
    4. from django.db.models import Min, Max, Sum, Avg, Count
    5. 单个: models.Book.objects.aggregate(Min('price'))
    6. 多个: models.Book.objects.aggregate(Min('price'), Max('price'), Sum('price'), Avg('price'), Count('pk'))
    7. # 返回字典类型: {'price__avg': 值}
    8. # 分组查询 annotate
    9. # 作用: 分组.
    10. # 分组注意事项: 分组只能拿到分组的依据 以及 分组举和的结果. (拓展: 可多个分组, 多个分组就含有多个分组的依据.)
    11. # MySQL设置全局分组严格模式: set global sql_mode=only_full_group_by;
    12. # 使用:
    13. from django.db.models import Min, Max, Sum, Avg, Count
    14. # 默认分组: 对models点后面的表进行分组
    15. models.Book.objects.annotate(price_avg=Avg('price')).values('title', 'price_avg')
    16. # 特殊情况使用: Count一般统计唯一字段 或 主键. 使用时可以简写
    17. models.Book.objects.annotate(author_count=Count('authors__id')).values('title', 'author_count')
    18. 简写: models.Book.objects.annotate(author_count=Count('authors')).values('title', 'author_count')
    19. # 指定分组: 分组依据publish__id
    20. models.Book.objects.values('publish__id').annotate(publish_count=Count('title')).values('publish_count', 'publish__id', 'publish__name')

     

    F与Q查询

    1. F查询

    像之前我们所了解的一些过滤的例子和操作都是在针对字段值和某一个常量之间作比较,但是如果我们要针对两个字段值作比较的话就不行了,这就涉及到这个F查询了

    1. """
    2. # 作用: 能够帮助你直接获取到表中某个字段对应的数据
    3. # 使用:
    4. from django.db.models import F
    5. # 获取到某个字段对应的数据
    6. F("字段__条件")
    7. # 查询字段对应的数据是数字类型可以直接加减运算:
    8. F('字段__条件') + 500
    9. # 字符类型需要借助Concat和Value方法
    10. from django.db.models.functions import Concat
    11. from django.db.models import Value
    12. Concat(F('字段__条件'), Value("str"))
    13. 注意: 查询字段对应的数据是字符类型不能直接进行拼接. 否则操作的字段对应的所有数据将变成空白.
    14. """
    15. from django.db.models import F
    16. # 1. 查询卖出数大于库存数的书籍
    17. res = models.Book.objects.filter(sale__gt=F('stock'))
    18. print(res) # , ]>
    19. # 2. 将所有书籍的价格提升500块
    20. res = models.Book.objects.update(price=F('price') + 500)
    21. print(res) # .update方法返回受影响的行数 7
    22. # 3. 将所有书的名称后面加上爆款两个字
    23. from django.db.models.functions import Concat
    24. from django.db.models import Value
    25. models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
    26. # models.Book.objects.update(title=F('title') + '爆款') # 这样指定的字段title所有对应的数据全部变成空白.

    2. Q查询

    1. """
    2. # 作用: filter的字段筛选条件指定多个, 默认是and连接. 要实现or或者not需要借助Q查询
    3. # 使用:
    4. from django.db.models import Q
    5. Q(字段__条件=值)
    6. # 连接条件and的3种情况
    7. 1. filter中指定多个参数逗号隔开: filter(参数1, 参数2)
    8. 2. 查询指定多个逗号隔开: filter(Q(), Q())
    9. 3. 使用&连接符: filter(Q() & Q())
    10. # 连接条件or
    11. filter(Q() | Q())
    12. # 连接条件not
    13. filter(~Q() | Q())
    14. # Q查询的高阶用法: 让左边指定的变量形式的查询条件可以是字符串
    15. q = Q()
    16. q.connecter = 'or' # 指定连接符. 不指定默认and
    17. q.children.append(Q('字段__条件', 值))
    18. res = models.XXX.objects.filter(q)
    19. """
    20. from django.db.models import Q
    21. # 1. 查询卖出数大于100 和 价格小于900的书籍 --> 连接条件 and
    22. # res = models.Book.objects.filter(sale__gt=100, price__lt=900)
    23. # res = models.Book.objects.filter(Q(sale__gt=100), Q(price__lt=900))
    24. res = models.Book.objects.filter(Q(sale__gt=100) & Q(price__lt=900))
    25. print(res) # ]>
    26. # 2. 查询卖出数大于100或者价格小于600的书籍 --> 连接条件 or
    27. res = models.Book.objects.filter(Q(sale__gt=100) | Q(price__lt=600))
    28. print(res) # , , , , , ]>
    29. # 3. 查询卖出数不大于100或者价格小于600的书籍 --> 连接条件 not
    30. res = models.Book.objects.filter(~Q(sale__gt=100) | Q(price__lt=600))
    31. print(res) # ]>
    32. # 4. Q的高阶用法: 能够将查询条件的左边变量的形式变成字符串的形式
    33. q = Q() # 第一步: 实例化一个q对象
    34. q.connector = 'or' # 第二步: 定义连接条件
    35. q.children.append(('sale__gt', 100)) # 第三步: 指定字符串形式的查询字段条件, 以及范围100
    36. q.children.append(('price__lt', 600))
    37. res = models.Book.objects.filter(q) # 第四步: 将q对象传入filter
    38. print(res)

  • 相关阅读:
    《刺客信条:起源》画面BUG?我先“退”一步!
    Web 3 中的零知识技术:现在和未来
    【1422. 分割字符串的最大得分】
    【Java】集合与顶级接口Collection
    IATF16949认证审核要点
    AE动画调整
    java springboot 通过ConfigurationProperties给第三方bean注入属性
    优化算法 - 动量法
    关于ETL的两种架构(ETL架构和ELT架构)
    Linux服务器——进程/线程池
  • 原文地址:https://blog.csdn.net/m0_71115526/article/details/134441750