1. 程式人生 > >(模型四)模型查詢

(模型四)模型查詢

簡介

  • 查詢集表示從資料庫中獲取的物件集合
  • 查詢集可以含有零個、一個或多個過濾器
  • 過濾器基於所給的引數限制查詢的結果
  • 從Sql的角度,查詢集和select語句等價,過濾器像where和limit子句
  • 接下來主要討論如下知識點
    • 查詢集
    • 欄位查詢:比較運算子,F物件,Q物件

查詢集

  • 在管理器上呼叫過濾器方法會返回查詢集
  • 查詢集經過過濾器篩選後返回新的查詢集,因此可以寫成鏈式過濾
  • 惰性執行:建立查詢集不會帶來任何資料庫的訪問,直到呼叫資料時,才會訪問資料庫
  • 何時對查詢集求值:迭代,序列化,與if合用
  • 返回查詢集的方法,稱為過濾器
    • all()               獲取所有資料
    • filter()            篩選,獲取滿足條件的資料
    • exclude()       獲取不滿足條件的資料
    • order_by()     排序
    • values()         一個物件構成一個字典,然後構成一個列表返回
  • 寫法:
filter(鍵1=值1,鍵2=值2)
等價於
filter(鍵1=值1).filter(鍵2=值2)
  • 返回單個值的方法
    • get():返回單個滿足條件的物件
      • 如果未找到會引發"模型類.DoesNotExist"異常
      • 如果多條被返回,會引發"模型類.MultipleObjectsReturned"異常
    • count():返回當前查詢的總條數
    • first():返回第一個物件
    • last():返回最後一個物件
    • exists():判斷查詢集中是否有資料,如果有則返回True

限制查詢集

  • 查詢集返回列表,可以使用下標的方式進行限制,等同於sql中的limit和offset子句
  • 注意:不支援負數索引
  • 使用下標後返回一個新的查詢集,不會立即執行查詢
  • 如果獲取一個物件,直接使用[0],等同於[0:1].get(),但是如果沒有資料,[0]引發IndexError異常,[0:1].get()引發DoesNotExist異常

查詢集的快取

  • 每個查詢集都包含一個快取來最小化對資料庫的訪問
  • 在新建的查詢集中,快取為空,首次對查詢集求值時,會發生資料庫查詢,django會將查詢的結果存在查詢集的快取中,並返回請求的結果,接下來對查詢集求值將重用快取的結果
  • 情況一:這構成了兩個查詢集,無法重用快取,每次查詢都會與資料庫進行一次互動,增加了資料庫的負載
print([e.title for e in Entry.objects.all()])   拿資料了
print([e.title for e in Entry.objects.all()])
  • 情況二:兩次迴圈使用同一個查詢集,第二次使用快取中的資料
querylist=Entry.objects.all()  沒拿資料
print([e.title for e in querylist])  拿資料了
print([e.title for e in querylist])
  • 何時查詢集不會被快取:當只對查詢集的部分進行求值時會檢查快取,但是如果這部分不在快取中,那麼接下來查詢返回的記錄將不會被快取,這意味著使用索引來限制查詢集將不會填充快取,如果這部分資料已經被快取,則直接使用快取中的資料

欄位查詢

  • 實現where子名,作為方法filter()、exclude()、get()的引數
  • 語法:屬性名稱(模型類中的屬性)__比較運算子=值
  • __表示兩個下劃線,左側是屬性名稱,右側是比較型別
  • 對於外來鍵,使用“屬性名_id”表示外來鍵的原始值
  • 轉義:like語句中使用了%與,匹配資料中的%與,在過濾器中直接寫,例如:filter(title__contains="%")=>where title like '%\%%',表示查詢標題中包含%的

比較運算子

  • exact:表示判等,大小寫敏感;如果沒有寫“ 比較運算子”,表示判等
filter(isDelete=False)
  • contains:是否包含,大小寫敏感
exclude(btitle__contains='傳')
  • startswith、endswith:以value開頭或結尾,大小寫敏感
exclude(btitle__endswith='傳')
  • isnull、isnotnull:是否為null
filter(btitle__isnull=False)
  • 在前面加個i表示不區分大小寫,如iexact、icontains、istarswith、iendswith
  • in:是否包含在範圍內
filter(pk__in=[1, 2, 3, 4, 5])
  • gt、gte、lt、lte:大於、大於等於、小於、小於等於
filter(id__gt=3)
  • year、month、day、week_day、hour、minute、second:對日期間型別的屬性進行運算
filter(bpub_date__year=1980)
filter(bpub_date__gt=date(1980, 12, 31))
  • 跨關聯關係的查詢:處理join查詢
    • 語法:模型類名 <屬性名> <比較>
    • 注:可以沒有__<比較>部分,表示等於,結果同inner join
    • 可返向使用,即在關聯的兩個模型中都可以使用
filter(heroinfo_ _hcontent_ _contains='八')
  • 查詢的快捷方式:pk,pk表示primary key,預設的主鍵是id
filter(pk__lt=6)

例如:
models.py
from django.db import models

class BookInfo(models.Model):
    btitle = models.CharField(max_length=20)
    bpub_date = models.DateTimeField(db_column='pub_date')  # db_column:欄位的名稱,如果未指定,則使用屬性的名稱
    bread = models.IntegerField(default=0)  # 閱讀量
    bcommet = models.IntegerField(null=False)  # null=False表示不能為空
    isDelete = models.BooleanField(default=False)

    class Meta:
        db_table = 'bookinfo'  # 預設為booktest_bookinfo

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
{% for book in list %}
<li>{{book.btitle}}</li>
{% endfor %}
</body>
</html>

views.py

from django.shortcuts import render
from booktest.models import *


def index(request):
list1 = BookInfo.objects.filter(heroinfo__hcontent__contains='八') # 當前英雄的內容中是否包含‘八’
list2 = BookInfo.objects.filter(pk__gt=3) # 查詢id>3的書的資訊
context = {'list': list2}
return render(request, 'booktest/index.html', context)

聚合函式

  • 使用aggregate()函式返回聚合函式的值
  • 函式:Avg,Count,Max,Min,Sum
from django.db.models import Max
maxDate = list.aggregate(Max('bpub_date'))

例如:
from django.shortcuts import render
from booktest.models import *
from django.db.models import Max


def index(request):
    list1 = BookInfo.objects.filter(heroinfo__hcontent__contains='')  # 當前英雄的內容中是否包含‘八’
    list2 = BookInfo.objects.filter(pk__gt=3)  # 查詢id>3的書的資訊
    list3 = BookInfo.objects.aggregate(Max('bpub_date'))
    context = {'list': list3}
    return render(request, 'booktest/index.html', context)
  • count的一般用法:
count = list.count()

F物件(資料表中兩個列比較)

  • 可以使用模型的欄位A與欄位B進行比較,如果A寫在了等號的左邊,則B出現在等號的右邊,需要通過F物件構造
list.filter(bread__gte=F('bcommet'))
  • django支援對F()物件使用算數運算
list.filter(bread__gte=F('bcommet') * 2)
  • F()物件中還可以寫作“模型類__列名”進行關聯查詢
list.filter(isDelete=F('heroinfo__isDelete'))
  • 對於date/time欄位,可與timedelta()進行運算
list.filter(bpub_date__lt=F('bpub_date') + timedelta(days=1))

例如:
from django.shortcuts import render
from booktest.models import *
from django.db.models import Max


def index(request):
    # list4 = BookInfo.objects.filter(bread__gt=20)  # 閱讀量>20的書
   list4 = BookInfo.objects.filter(bread__gt=F('bcommet'))  # 閱讀量>評論量
    context = {'list': list4}
    return render(request, 'booktest/index.html', context)

Q物件

  • 過濾器的方法中關鍵字引數查詢,會合併為And進行
  • 需要進行or查詢,使用Q()物件
  • Q物件(django.db.models.Q)用於封裝一組關鍵字引數,這些關鍵字引數與“比較運算子”中的相同
from django.db.models import Q
list.filter(Q(pk_ _lt=6))
  • Q物件可以使用&(and)、|(or)操作符組合起來
  • 當操作符應用在兩個Q物件時,會產生一個新的Q物件
下面三個等價:
list.filter(pk_ _lt=6,bcommet_ _gt=10)

list.filter(pk_ _lt=6).filter(bcommet_ _gt=10)
list.filter(Q(pk_ _lt=6) | Q(bcommet_ _gt=10))  不推薦Q物件用於‘或’關係
  • 使用~(not)操作符在Q物件前表示取反
list.filter(~Q(pk__lt=6))
  • 可以使用&|~結合括號進行分組,構造做生意複雜的Q物件
  • 過濾器函式可以傳遞一個或多個Q物件作為位置引數,如果有多個Q物件,這些引數的邏輯為and
  • 過濾器函式可以混合使用Q物件和關鍵字引數,所有引數都將and在一起,Q物件必須位於關鍵字引數的前面