DJANGO之ORM补充(aggregate/annotate/F&Q/extra/原生SQL等)
一 分组和聚合查询
实例代码:
class Book(models.Model): '''书籍信息''' title = models.CharField(max_length=32) price = models.DecimalField(max_digits=5, decimal_places=2) # 一共5位,保留两位小数 publish = models.ForeignKey("Publish",on_delete=models.CASCADE) authors = models.ManyToManyField("Author") #建立的多对多的关系 class Publish(models.Model): '''出版社信息''' title =models.CharField(max_length=64) class Author(models.Model): '''作者信息''' name = models.CharField(max_length=32)
1.1 分组查询 aggregate(*args, **kwargs)
只对一个组进行聚合
# 查询所有图书的平均价格
# aggregate()返回一个包含一些键值对的字典。键的名称是按照字段和聚合函数的名称自动生成出来的。
from django.db.models import Avg, Sum, Count, Max, Min
print(models.Book.objects.all().aggregate(Avg("price"))) # {'price__avg': 34.5}
# 指定键名称
print(models.Book.objects.all().aggregate(avg_price=Avg("price"))) # {'avg_price': 34.5}
# 向aggregate()中添加其他聚合参数
print(models.Book.objects.all().aggregate(Avg("price"),Max("price"), Min("price"),Sum("price"),Count("price")))
# {'price__avg': 34.5, 'price__min': Decimal('24.00'), 'price__count': 6, 'price__max': Decimal('45.00'), 'price__sum': Decimal('207.00')}
1.2 分组查询 annotate(*args,**kwargs)
为QuerySet中每一个对象都生成一个独立的汇总值, 是对分组完之后的结果进行的聚合
# 1.统计每一本书的作者个数
# 方式一:
models.Book.objects.all().annotate(author_num=Count("authors__name")).values('title',"author_num")
# 方式二:
book_objs = models.Book.objects.all().annotate(author_num=Count("authors__name"))
for book_obj in book_objs:
print(book_obj.title, book_obj.author_num)
# 2.统计每一个出版社的最便宜的书
# 方式一:
models.Publish.objects.all().annotate(min_price=Min("book__price")).values("title", "min_price")
# 方式二:
publish_objs = models.Publish.objects.annotate(min_price=Min("book__price"))
for publish_obj in publish_objs:
print(publish_obj.title, publish_obj.min_price)
# 方式三:
models.Book.objects.values("publish__title").annotate(min_price=Min('price'))
# 注意:values内的字段即group by的字段,也就是分组条件
# 3.统计不止一个作者的图书
models.Book.objects.all().annotate(author_num=Count('authors__name')).filter(author_num__gt=1).values('title')
# 4.查询各个作者出的书的总价格:
models.Author.objects.all().annotate(book_sum_price=Sum('book__price')).values('name','book_sum_price')
models.Book.objects.values('authors__name').annotate(book_sum_price=Sum('price')) #默认将分组数据加入对象中
# 5.根据作者书籍总价格对作者进行排序:
models.Author.objects.all().annotate(book_sum_price=Sum('book__price')).values('name').order_by('-book_sum_price')
# 6.统计以“长安”开头的书籍的作者个数:
models.Book.objects.filter(title__istartswith='长安').annotate(author_num = Count('authors__name')).values('title','author_num')
二 F查询和Q查询
在实际应用中,往往需要对两个字段的值做比较,这是我们可以使用Django 提供的 F函数来做比较。F() 的实例可以在查询中引用字段,来比较同一个 model 实例中两个不同字段的值。
2.1 F查询
# 查看评论数大于阅读数的书
from django.db.models import F,Q
obj = models.Book.objects.filter(comment_num__gt=F("read_num")))
# Django 支持 F()对象之间以及 F()对象和常数之间的加减乘除和取模的操作
# 查询评论数大于阅读数2倍的书
models.Book.objects.filter(comment_num__gt=F('read_num')*2)
# 修改字段的值
models.Book.objects.all().update(price=F('price')+1) #对图书馆里的每一本书的价格上调1块钱
说白了,F查询就是获取一个字段的值,然后做一些操作
2.2 Q查询
filter()等方法中的关键字参数查询都是进行“AND”操作的。如果需要执行更复杂的查询(例如OR语句),我们可以使用Q对象
from django.db.models import F,Q
models.UserInfo.objects.filter(Q(id__gt=1))
models.UserInfo.objects.filter(Q(id=8) | Q(id=2)) #or
models.UserInfo.objects.filter(Q(id=8) & Q(id=2)) #and
from django.db.models import F,Q q1 = Q() # 对象 q1.connector = 'OR' # 设置对象连接方式 q1.children.append(('uid__gt', 1)) q1.children.append(('uid', 10)) q1.children.append(('uid', 9)) q2 = Q() q2.connector = 'OR' q2.children.append(('age', 18)) q2.children.append(('age', 19)) q2.children.append(('age', 20)) q3 = Q() q3.connector = 'AND' q3.children.append(('uid', 1)) q3.children.append(('uid', 2)) q2.add(q3, 'OR') con = Q() con.add(q1, 'AND') con.add(q2, 'AND') print(con) #(AND: (OR: ('uid__gt', 1), ('uid', 10), ('uid', 9)), (OR: ('age', 18), ('age', 19), ('age', 20), (AND: ('uid', 1), ('uid', 2))))
condition_list = {
'uid':{7,8,9},
'username':{'joe2','joe1'},
}
con = Q()
for k,v in condition_list.items():
q = Q()
q.connector = 'OR'
for i in v:
q.children.append((k,i))
con.add(q,'AND')
list = models.UserInfo.objects.filter(con).values('username')
print(con) #(AND: (OR: ('uid', 8), ('uid', 9), ('uid', 7)), (OR: ('username', 'joe2'), ('username', 'joe1')))
print(list) #<QuerySet [{'username': 'joe1'}, {'username': 'joe2'}]>
Q应用--自定义查询复杂条件
三 extra
额外查询条件以及相关表,排序
extra(self, select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
# models.xxx.objects.extra(select={'new_id': "select col from sometable where othercol > %s"}, select_params=(1,))
# models.xxx.objects.extra(where=['headline=%s'], params=['Lennon'])
# models.xxx.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
# models.xxx.objects.extra(select={'new_id': "select id from tb where id > %s"}, select_params=(1,), order_by=['-nid'])
# a. 映射
# select
# select_params
# 转为SQL语句:select 替代此处 from 表
# b. 条件
# where
# params
# 转为SQL语句:select * from 表 where 替代此处
# c. 表
# tables
# 转为SQL语句:select * from 表,替代此处
# d. 排序
# order_by
# 转为SQL语句:select * from 表 order by 替代此处
实例
models.UserInfo.objects.extra(
select={'newid':'select count(1) from app01_usertype where id>%s'},
select_params=[1,],
where = ['age>%s'],
params=[18,],
order_by=['-age'],
tables=['app01_usertype']
)
# 转换为SQL语句:
"""
select
app01_userinfo.id,
(select count(1) from app01_usertype where id>1) as newid
from app01_userinfo,app01_usertype
where
app01_userinfo.age > 18
order by
app01_userinfo.age desc
"""
四 原生sql
from django.db import connection, connections
cursor = connection.cursor() # connection=default数据
#cursor = connections['db2'].cursor() #指定其他数据库
cursor.execute("SELECT * from app01_userinfo where uid = %s", 7)
row = cursor.fetchone()
#row = cursor.fetchall()
五 其他
5.1 获取SQL语句
a = models.Book.objects.filter(title__istartswith='长安').annotate(author_num = Count('authors__name')).values('title','author_num')
print(a.query) # 获取的即为SQL语句

浙公网安备 33010602011771号