假如有一個Model Coffee如下:
class Coffee(models.Model):
name = models.CharField(max_length=60)
price = models.IntegerField()
country = models.ForeignKey(Country)class Country(models.Model):
name = models.CharField(max_length=60)
QuerySet
開始介紹之前,首先須介紹什麼是QuerySet,顧名思義就是一組查詢後的集合。
QuerySet允許你向資料庫作查詢,但是因為QuerySet的查詢是Lazy的,所以只有在需要顯示資料的時候才會直接存取資料庫。
為了避免頻繁的向資料庫查詢,QuerySet除了有Lazy的特性,還包含了Cache的功能,每一組QuerySet都有Cache,以減少資料庫的存取。
另外,QuerySet也包含了串接的功能,也就是可以連續下不同的query,最後只會有一次的資料庫存取。
EX:
>>> Coffee.objects.filter(
... country__name__startswith='Africa'
... ).filter(
... price__gte=100
... )
=> 列出產地名稱開頭為 Africa
且價格高於100的咖啡物件。
回傳QuerySet的方法
all()
all() 是最容易的查詢語法,可以將所有的物件都列出來。
Ex: Coffee.objects.all()
filter(**kwargs) / exclude(**kwargs)
filter(**kwargs)可以根據代入的參數來決定輸出的物件。
反之,exclude(**kwargs)是輸出排除輸入的參數以外的物件。
Ex: Coffee.objects.filter(name='latte')
=> 列出名稱為latte的 物件
Coffee.objects.exclude(name='latte')
=> 列出名稱為非latte的物件
annotate(*args, **kwargs)
假如將原本的Coffee model改寫如下:
class Coffee(models.Model):
name = models.CharField(max_length=60)
price = models.IntegerField()
country = models.ForeignKey(Country)
flavor = models.ManyToManyField(Flavor)class Country(models.Model):
name = models.CharField(max_length=60)class Flavor(models.Model):
name = models.CharField(max_length=60)
當需要得知某個Coffee model底下的口味數量可以用annotate。
from django.db.models import Count
c = Coffee.objects.annotate(Count(flavor))
c[0].flavor__count # 顯示幾種口味
--> 5
=> 可以看出在Flavor model上並沒有count的欄位,但是利用annotate就可以將這個欄位暫時的填入目前的QuerySet
order_by()
將搜尋出來的QuerySet利用order_by的順序再次排序。
EX: Coffee.objects.filter(country__name='Africa').order_by('-price', 'name')
將Coffee的Object利用filter搜尋出來之後,再將此QuerySet按照price降冪,name升冪的方式排序
distinct()
當搜尋多個Table時,有可能會出現重複的資料,利用 distinct()
即可以消除重複的項目。
union()
>>> qs1.union(qs2, qs3)
union()是在django 1.11所新增的功能,可以將兩個QuerySet合併起來。
不是回傳QuerySet的方法
get()
利用get()可以直接取得物件,其效果等同於filter()[0]。
當物件不存在時,會拋出例外 DoesNotExist
。
aggregate(*args, **kwargs)
類似 annotate()
,不過aggregate是回傳一組dict。
Ex:
from django.db.models import Count
c = Coffee.objects.aggregate(Count(flavor))
--> {'flavor__count': 5}
exist()
回傳True, 如果QuerySet存在
限制取得物件的數量
當輸出為QuerySet()時,可以在查詢語句後方加入範圍來限制資料數量。
EX: Coffee.objects.all()[:10]
取得前十個物件。
EX: Coffee.objects.filter(price='100')[2:5]
取得價格為100的第三~第六個物件。
欄位的查詢
有時候,我們並不只是要特定的名稱、價格,我們會需要針對欄位作不同的查詢。
查詢格式:field__lookuptype=value
數字,日期範圍的查詢可以使用:
GT (Greater than): 大於
LT (Less than): 小於
GTE (Greater Than or Equal): 大於或等於
LTE (Less Than or Equal): 小於或等於
名稱的查詢可以使用:
startswith: 大小寫,開頭的字串相符
istartswith: 大小寫不須一樣,開頭的字串相符
endswith: 大小寫,結尾的字串相符
iendswith: 大小寫不須一樣,結尾的字串相符
exact: 精確的比對
iexact: 不精確的比對(大小寫不須相同)
contains: 包含此文字
查詢foreign key的值:
EX:
Coffee.objects.filter(country__name='Africa')
=> 查詢Coffee object中,country name為Africa的Object。
小結
研究django所提供的query model的方法之後,針對不同的使用需求可以用不同的方法,了解之後,就不會只是使用filter(), all(), get()了。