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)
View Code

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语句
posted @ 2018-09-29 17:09  Joe1991  阅读(201)  评论(0)    收藏  举报