2-7.ORM进阶
如何查看SQL语句
1.如果当前对象是queryset那么可以直接点query查找该对象内部SQL语句
2.配置文件settings.py(只要执行orm语句都会自动打印SQL语句)
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}
神奇的双下划线查询
# 1.查询价格大于800的书籍
res = models.Books.objects.filter(price__gt=800)
print(res)
# 2.查询价格小于800的书籍
res = models.Books.objects.filter(price__lt=800)
print(res)
# 3.查询价格大于等于800的书籍
res = models.Books.objects.filter(price__gte=800)
print(res)
# 4.查询价格大于等于800的书籍
res = models.Books.objects.filter(price__lte=800)
print(res)
# 5.查询价格是989.45 或者278.89 或者888.21
res = models.Books.objects.filter(price__in=["888.21","278.89","989.45"])
print(res)
# 6.查询加个在200到800之间的书籍
res = models.Books.objects.filter(price__range=(200,800))
print(res)
# 7.查询书籍名称中包含字母p的书(区分大小写)
res = models.Books.objects.filter(title__contains='p')
print(res)
res = models.Books.objects.filter(title__icontains='p')
print(res)
# 8.查询书籍是否以...开头 ...结尾
res = models.Books.objects.filter(title__startswith=)
res1 = models.Books.objects.filter(title__endswith=)
# 9.查询出版日期是2021的书(常用)
res = models.Books.objects.filter(publish_time__year=2021)
res1 = models.Books.objects.filter(publish_time__month=11)
print(res,res1)
正反向理论
正向查询
书籍对象查出版社对象 外键字段在书表中 # 正向查询
书籍对象查作者对象 外键字段在书表中 # 正向查询
作者对象查作者详情 外键字段在作者中 # 正向查询
反向查询
出版社查书籍对象 外键字段不在出版社表中 # 反向查询
作者查书籍对象 外键字段不在作者表中 # 反向查询
作者详情查作者 外键字段不在作者详情表中 # 反向查询
"""
查询数据的时候如果外键字段"在你的手上"则为正向查询
如果外键字段不在则为反向查询
"""
口诀:
正向查询按外键字段 ...
反向查询按表名小写 ...
聚合查询和分组查询
aggregate()方法详解
aggregate的中文意思是聚合, 源于SQL的聚合函数。Django的aggregate()方法作用是对一组值(比如queryset的某个字段)进行统计计算,并以字典(Dict)格式返回统计计算结果。django的aggregate方法支持的聚合操作有AVG / COUNT / MAX / MIN /SUM 等。
聚合函数
max min sum count avg
from django.db.models import Max,Min,Sum,Count,Avg
aggregate()
是QuerySet
的一个终止子句,意思是说,它返回一个包含一些键值对的字典。
键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。
from django.db.models import Max,Min,Sum,Count,Avg
# 1.统计所有书籍的总价格
# res = models.Book.objects.aggregate(Sum('price'))
# print(res)
# 2.统计所有书籍的总数
# res = models.Book.objects.aggregate(Count('pk'))
# print(res)
# 3.统计价格最高的
# res = models.Book.objects.aggregate(Max('price'))
# print(res)
annotate()方法详解
理解是分组(Group By)。如果你想要对数据集先进行分组然后再进行某些聚合操作或排序时,需要使用annotate方法来实现。与aggregate方法不同的是,annotate方法返回结果的不仅仅是含有统计结果的一个字典,而是包含有新增统计字段的查询集(queryset).
F查询与Q查询
F查询
F的功能是获取数据库中字段原有的数据
from django.db.models import F
案例
将所有书籍的价格提升100块
from django.db.models import F
models.Book.objects.update(price=F('price')+100)
2.将所有书籍名称后面加上爆款后缀
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F('title'), Value('爆款')))
Q查询
filter()
等方法中逗号隔开的条件是与的关系。 如果你需要执行更复杂的查询(例如OR
语句),你可以使用Q对象
。
from django.db.models import Q
逗号分隔为and关系
|分隔为or关系
~分隔为not关系
示例1:
查询 卖出数大于100 或者 价格小于100块的
from django.db.models import Q
models.Product.objects.filter(Q(maichu__gt=100)|Q(price__lt=100))
对条件包裹一层Q时候,filter即可支持交叉并的比较符
示例2:
查询 库存数是100 并且 卖出数不是0 的产品
models.Product.objects.filter(Q(kucun=100)&~Q(maichu=0))
我们可以组合&
和|
操作符以及使用括号进行分组来编写任意复杂的Q
对象。
同时,Q
对象可以使用~
操作符取反,这允许组合正常的查询和取反(NOT
) 查询。
示例3:
查询产品名包含新款, 并且库存数大于60的
models.Product.objects.filter(Q(kucun__gt=60), name__contains="新款")
查询函数可以混合使用Q 对象
和关键字参数。所有提供给查询函数的参数(关键字参数或Q
对象)都将"AND”在一起。但是,如果出现Q
对象,它必须位于所有关键字参数的前面。
orm事务操作
事务:ACID
A原子性
C一致性
I独立性
D持久性
作为上下文管理器来使用
from django.db import transaction
with transaction.atomisc():
# sql1
# sql2
# sql3
# 在with代码块内写的所有orm操作都是属于同一个事务
orm查询优化
only与defer
only
对象点击only括号内填写的字段名称不会再走数据库查询
但是点击括号内不存在的字段名称则每次都会走数据库查询
defer
与only互为反操作
select_related与prefetch_related
select_related
select_related括号内只能放外键字段 并且不支持多对多外键字段
内部是连表操作 会将外键关联的表与当前表拼接 之后将所有的数据全部封装到数据对象中之后对象无论查询哪个表的数据都不再走数据库查询
prefetch_related
内部是子查询操作
字段参数之choices
用户表
性别字段
学历字段
在职状态
...
"""如果我们在设计表字段的时候 有一些字段能够完全列举出所有可能的情况"""
# 这个时候推荐使用choices参数
class User(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
gender_choices = (
(1, '男性'),
(2, '女性'),
(3, '其他')
)
gender = models.IntegerField(choices=gender_choices)
user_obj = models.User.objects.filter(pk=1).first()
user_obj.gender # 1
user_obj.get_gender_display() # 男性
'''如果没有对应关系则返回数据本身'''
多对多关系表的三种创建方式
全自动
在我们之前创建多对多表的时候,一直用的都是全自动的方式来创建第三张关系表的
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8, decimal_places=2)
# 创建多对多关系字段
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=32)
好处:
在于 django orm会自动帮你创建第三张关系表
还内置了操作第三张表的方法:add set remove clear
不足:
但是它只会帮你创建两个表的关系字段 不会再额外添加字段
虽然方便 但是第三张表的扩展性较差 无法随意的添加额外的字段
纯手写(不推荐)
class Book(models.Model):
title = models.CharField(max_length=32)
class Authors(models.Model):
name = models.CharField(max_length=32)
class Book2Authors(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Authors')
# 可以添加任意字段
create_time = models.DateField(auto_now_add=True)
好处:
可以在第三张表添加任意字段
不足:
纯手写比较麻烦, 没有orm查询的方法
半自动(推荐使用)
class Book(models.Model):
title = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Authors', through='Book2Authors', through_fields=("book", "authors"))
# through 记录与哪张表的关系表,through_field来指定 哪几个外键字段
class Authors(models.Model):
name = models.CharField(max_length=32)
class Book2Authors(models.Model):
book = models.ForeignKey(to='Book')
authors = models.ForeignKey(to='Authors')
# 可以扩展任意字段
当ManyToManyField只有一个参数to的情况下,orm会自动创建第三张表,如果加了through和through_fields,那么orm就不会自动帮你创建第三张表,但是它会在内部帮你维护关系,让你能够继续使用orm的跨表查询方法。
through参数,自己指定第三张表
through_fields参数,要写一个元组,告诉第三张表,通过这个元组里的两个字段知道是那两张表多对多,第三张表通过哪个字段查询 就把哪个字段放前面
。