單表查詢之下划線
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 獲取id大於1 且 小於10的值
models.Tb1.objects.filter(id__in=[11, 22, 33]) # 獲取id等於11、22、33的數據
models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in
models.Tb1.objects.filter(name__contains="ven") # 獲取name字段包含"ven"的
models.Tb1.objects.filter(name__icontains="ven") # icontains大小寫不敏感
models.Tb1.objects.filter(id__range=[1, 3]) # id范圍是1到3的,等價於SQL的bettwen and
類似的還有:startswith,istartswith, endswith, iendswith
date字段還可以:
models.Class.objects.filter(first_day__year=2017)
#獲取id大於1且小於10的值
print(models.Book.objects.filter(id__lt=10,id__gt=1))
# 查詢 id 在 [1, 4, 5, 7]中的結果
print(models.Book.objects.filter(id__in=[1,4,5,7]))
# contains 字段包含指定值的
print(models.Book.objects.filter(title__contains="小單"))
# icontains 忽略大小寫包含指定值
print(models.Book.objects.filter(title__icontains="NI"))
# 判斷id值在 哪個區間的 SQL語句中的between and 1<= <=3
print(models.Book.objects.filter(id__range=[1,3]))
# 日期和時間字段還可以有以下寫法
ret = models.Person.objects.filter(birthday__year=2000)
ret = models.Person.objects.filter(birthday__year=2000, birthday__month=5)
跨表查詢操作
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
# 與AuthorDetail建立一對一的關系
authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE)
class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
# 與Publish建立一對多的關系,外鍵字段建立在多的一方
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
# 與Author表建立多對多的關系,ManyToManyField可以建在兩個模型中的任意一個,自動創建第三張表
authors=models.ManyToManyField(to='Author',)
View Code
基於對象查詢(子查詢)
按字段(publish)
一對多 book -----------------> publish
<----------------
book_set.all()
正向查詢按字段:
查詢python這本書籍的出版社的郵箱
python=models.Book.objects.filter(title="python").first()
print(python.publish.email)
反向查詢按 表名小寫_set.all()
蘋果出版社出版的書籍名稱
publish_obj=models.Publish.objects.filter(name="蘋果出版社").first()
for obj in publish_obj.book_set.all():
print(obj.title)
按字段(authors.all())
多對多 book -----------------------> author
<----------------
book_set.all()
查詢python作者的年齡
python = models.Book.objects.filter(title="python").first()
for author in python.authors.all():
print(author.name ,author.age)
查詢alex出版過的書籍名稱
alex=models.Author.objects.filter(name="alex").first()
for book in alex.book_set.all():
print(book.title)
按字段 authorDetail
一對一 author -----------------------> authordetail
<----------------
按表名 author
查詢alex的手機號
alex=models.Author.objects.filter(name='alex').first()
print(alex.authorDetail.telephone)
查詢家在山東的作者名字
ad_list=models.AuthorDetail.objects.filter(addr="shandong")
for ad in ad_list:
print(ad.author.name)
對應的sql:
select publish_id from Book where title="python"
select email from Publish where nid = 1
基於queryset和__查詢(join查詢)
正向查詢:按字段 反向查詢:表名小寫
查詢python這本書籍的出版社的郵箱
ret=models.Book.objects.filter(title="python").values("publish__email")
print(ret.query)
select publish.email from Book
left join Publish on book.publish_id=publish.nid
where book.title="python"
蘋果出版社出版的書籍名稱
方式1:
ret1 = models.Publish.objects.filter(name="蘋果出版社").values("book__title")
print("111111111====>", ret1.query)
# 方式2:
ret2 = models.Book.objects.filter(publish__name="蘋果出版社").values("title")
print("2222222222====>", ret2.query)
查詢alex的手機號
方式1:
ret = models.Author.objects.filter(name="alex").values("authorDetail__telephone")
方式2:
models.AuthorDetail.objects.filter(author__name="alex").values("telephone")
查詢手機號以151開頭的作者出版過的書籍名稱以及書籍對應的出版社名稱
ret = models.Book.objects.filter(authors__authorDetail__telephone__startswith="151").values('title', "publish__name")
print(ret.query)
# 1.正向查詢 基於對象 跨表查詢
book_obj = models.Book.objects.all().first() #對象
ret = book_obj.publisher # 和我這本書關聯的出版社對象
print(ret, type(ret))
ret = book_obj.publisher.name # 和我這本書關聯的出版社對象
print(ret, type(ret))
# 2.利用雙下划線 跨表查詢 雙下划線就表示跨了一張表,基於Queryset
ret = models.Book.objects.filter(id=1).values_list("publisher__name")
print(ret) #等同於 print( models.Book.objects.all().first().publisher.name)
print("反向查詢".center(80, "*"))
# 反向查詢 1. 基於對象查詢
publisher_obj = models.Publisher.objects.get(id=1) # 得到一個具體的對象
# ret = publisher_obj.book_set.all() #表名_set
ret = publisher_obj.books.all() #如果設置了related_name="books"
print(ret)
# 2. 基於雙下划線 基於Queryset
ret = models.Publisher.objects.filter(id=1).values_list("book__title")
print(ret)
View Code
聚合查詢
aggregate()是QuerySet 的一個終止子句,意思是說,它返回一個包含一些鍵值對的字典。
用到的內置函數:from django.db.models import Avg, Sum, Max, Min, Count
from django.db.models import Avg, Sum, Max, Min, Count
book_obj=models.Book.objects.all()
print(book_obj.aggregate(Max("price"))) #{'price__max': Decimal('9999.99')}
#指定一個名稱
print(book_obj.aggregate(max_price=Max("price"))) #{'max_price': Decimal('9999.99')}
#生成多個聚合
print(book_obj.aggregate(Max("price"),Min("price"),Avg("price"))) #{'price__max': Decimal('9999.99'), 'price__min': Decimal('10.00'), 'price__avg': 1507.141429}
分組查詢
1.和sql對比:
1.models.Employee Employee相當於sql中的from 后面的表名
2.annotate前面的values值相當於group by的字段
3.(a=Avg("salary"))里面如是跨表查詢就需要使用雙下划線,正查就字段__另一張表的字段,反查就另一張表明__字段
4.annotate后面的values 是select的字段
對應格式:select __ from ___ inner join ———— on ... group by ____
2.關鍵點:
1.queryset對象.annotate() annotate前面是queryset對象
2.annotate進行分組統計,按前面select的字段進行group by
3.annotate()返回值依然是queryset對象,增加了分組統計之后的鍵值對
1.ORM中values或者values_list 里面寫什么字段,就相當於select 什么字段
ORM分組查詢 每個部門名稱及部門的平均年齡
ret = models.Employee.objects.all().values("dept", "age")
SQL語句
"""
SELECT `employee`.`dept`, `employee`.`age` FROM `employee` LIMIT 21; args=()
"""
2.ORM中 annotate 前面是什么就按照什么分組
from django.db.models import Avg
ret = models.Employee.objects.values("province").annotate(a=Avg("salary")).values("province", "a")
相當於:
SELECT `employee`.`province`, AVG(`employee`.`salary`) AS `a` FROM `employee` GROUP BY `employee`.`province` ORDER BY NULL LIMIT 21; args=()
print("分組查詢".center(80, "*"))
3. ORM跨表分組查詢,queryset對象跨表查詢時使用雙下划線
ret = models.Person.objects.values("dept_id").annotate(a=Avg("salary")).values("dept__name", "a")
反向:
"""
SELECT `dept`.`name`, AVG(`person`.`salary`) AS `a` FROM `person` INNER JOIN `dept` ON (`person`.`dept_id` = `dept`.`id`) GROUP BY `person`.`dept_id`, `dept`.`name` ORDER BY NULL LIMIT 21; args=()
"""
4.查詢每一個部門的名稱和人數
#正向查詢:
models.emp.objects.values("dept_id").annotate(c=Count("name")).values("dept__name","c")
#反向查詢
models.dep.objects.values("name").annotate(c=Count("emp__name")).values("name","c")
SQL: select dep_name Count(emp.name) from emp inner join dep on .... group by dep_id
5.查詢每一個作者的名字及出版過的書籍的最高價
models.Author.objects.values('id').annotate(c=Max('book__price')).values("name","c")
##多對多的關系,在sql中跨了多張表
select __ from author inner join book_authors on .... inner join ... group by author.name
6.查詢每一本書作者的個數
models.Book.objects.values("id").annotate(c=Count("authors__name")).values("title","c")
ret=models.Book.objects.all().annotate(author_num=Count("author")) for book in ret: print("書名:{},作者數量:{}".format(book.title, book.author_num))
#查詢每一個分類的名稱及對應的文章數 models.Category.objects.values("id").annotate(c=Count("article__title")).values("title","c")
7.統計不止一個作者的圖書(過濾完后顯示) models.Book.objects.values("title").annotate(c=Count("authors__name")).filter(c__gt=1).values('name',"c")
8.查詢各個作者出的書的總價格 ret = models.Author.objects.all().annotate(price_sum=Sum("books__price")) for i in ret: print(i, i.name, i.price_sum)
extra --> 在執行ORM查詢的時候執行額外的SQL語句
# 查詢person表,判斷每個人的工資是否大於2000
ret = models.Person.objects.all().extra(
select={"gt": "salary > 2000"}
)
相當於:
SELECT (salary > 2000) AS `gt`, `person`.`id`, `person`.`name`, `person`.`salary`, `person`.`dept_id` FROM `person` LIMIT 21; args=()
直接執行原生的SQL語句,類似pymysql的用法
from django.db import connection
cursor = connection.cursor() # 獲取光標,等待執行SQL語句
cursor.execute("""SELECT * from person where id = %s""", [1])
row = cursor.fetchone()
print(row)
F查詢和Q查詢
F查詢
要對兩個字段的值做比較,Django 提供 F() 來做這樣的比較。
F() 的實例可以在查詢中引用字段,來比較同一個 model 實例中兩個不同字段的值。
1.查詢評論數大於收藏數的書籍
from django.db.models import F
models.Book.objects.filter(commnet_num__gt=F('keep_num'))
2.Django 支持 F() 對象之間以及 F() 對象和常數之間的加減乘除和取模的操作。
models.Book.objects.filter(commnet_num__lt=F('keep_num')*2)
3修改操作也可以使用F函數,比如將每一本書的價格提高30元
# 具體的對象沒有update(),QuerySet對象才有update()方法
models.Book.objects.all().update(price=F("price")+30)
刷單 把每一本書的賣出數都乘以3
obj = models.Book.objects.first()
obj.maichu = 1000 * 3
obj.save()
4.給每一本書的書名后面加上 第一版
from django.db.models.functions import Concat
from django.db.models import Value
models.Book.objects.update(title=Concat(F("title"), Value("第一版")))
Q查詢
如果你需要執行更復雜的查詢(例如OR語句),你可以使用Q對象。
from django.db.models import Q
1.查詢 賣出數大於1000,並且 價格小於100的所有書
ret = models.Book.objects.filter(maichu__gt=1000, price__lt=100)
print(ret)
2.查詢 賣出數大於1000,或者 價格小於100的所有書
ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100))
3. Q查詢和字段查詢同時存在時, 字段查詢要放在Q查詢的后面
ret = models.Book.objects.filter(Q(maichu__gt=1000) | Q(price__lt=100), title__contains="金老板")
Q().children查詢
Q().children,通過字段字符串查詢
q=Q()
##查詢出title字段中值為go的對象
q.children.append(("title","go"))
Book.objects.filter(q)
Out[11]: <QuerySet [<Book: go>]>
##查詢出title字段中值含有g的對象
q.children.append(("title__contains","g"))
Book.objects.filter(q)
Out[13]: <QuerySet [<Book: go>]>
q=Q() #不同的字段之間的關系默認為and
q.children.append(("title__contains","g"))
q.children.append(("price",100))
Book.objects.filter(q)
Out[17]: <QuerySet []>
q=Q()
q.connector="or" #不同的字段之間的關系更改為or
q.children.append(("title__contains","g"))
q.children.append(("price",100))
Book.objects.filter(q)
Out[22]: <QuerySet [<Book: go>]>