本文檔描述查詢集 API 的細節。它創建在模型和數據庫查詢指南的基礎上,因此在閱讀本文檔以前,你也許須要首先閱讀這兩部分的文檔。python
本文檔將通篇使用在數據庫查詢指南中用到的Weblog 模型的例子。mysql
在內部,能夠建立、過濾、切片和傳遞查詢集而不用真實操做數據庫。在你對查詢集作求值以前,不會發生任何實際的數據庫操做。正則表達式
你可使用下列方法對查詢集求值:算法
迭代。查詢集是可迭代的,它在首次迭代查詢集時執行實際的數據庫查詢。例如, 下面的語句會將數據庫中全部Entry 的headline 打印出來:sql
for e in Entry.objects.all(): print(e.headline)
注意:不要使用上面的語句來驗證在數據庫中是否至少存在一條記錄。使用 exists()方法更高效。數據庫
切片。 正如在限制查詢集中解釋的那樣, 可使用Python 的序列切片語法對一個查詢集進行分片。一個未求值的查詢集進行切片一般返回另外一個未求值的查詢集,可是若是你使用切片的」step「參數,Django 將執行數據庫查詢並返回一個列表。對一個已經求值的查詢集進行切片將返回一個列表。express
還要注意,雖然對未求值的查詢集進行切片返回另外一個未求值的查詢集,可是卻不能夠進一步修改它了(例如,添加更多的Filter,或者修改排序的方式),由於這將不太好翻譯成SQL並且含義也不清晰。django
序列化/緩存。 序列化查詢集的細節參見下面一節。本節提到它的目的是強調序列化將讀取數據庫。後端
repr()。 當對查詢集調用repr() 時,將對它求值。這是爲了在Python 交互式解釋器中使用的方便,這樣你能夠在交互式使用這個API 時當即看到結果。緩存
len()。 當你對查詢集調用len() 時, 將對它求值。正如你指望的那樣,返回一個查詢結果集的長度。
注:若是你只須要知道集合中記錄的個數(並不須要真實的對象),使用數據庫層級的SELECT COUNT(*) 計數將更加高效。爲此,Django 提供了 一個count() 方法.
list()。 對查詢集調用list() 將強制對它求值。例如:
entry_list = list(Entry.objects.all())
bool()。 測試一個查詢集的布爾值,例如使用bool()、or、and 或者if 語句將致使查詢集的執行。若是至少有一個記錄,則查詢集爲True,不然爲False。例如:
if Entry.objects.filter(headline="Test"): print("There is at least one Entry with the headline Test")
注:若是你須要知道是否存在至少一條記錄(而不須要真實的對象),使用 exists() 將更加高效。
若是你Pickle一個查詢集,它將在Pickle 以前強制將全部的結果加載到內存中。Pickle 一般用於緩存以前,而且當緩存的查詢集從新加載時,你但願結果已經存在隨時準備使用(從數據庫讀取耗費時間,就失去了緩存的目的)。這意味着當你Unpickle查詢集時,它包含Pickle 時的結果,而不是當前數據庫中的結果。
若是此後你只想Pickle 必要的信息來從數據庫從新建立查詢集,能夠Pickle查詢集的query 屬性。而後你可使用相似下面的代碼從新建立原始的查詢集(不用加載任何結果):
>>> import pickle >>> query = pickle.loads(s) # Assuming 's' is the pickled string. >>> qs = MyModel.objects.all() >>> qs.query = query # Restore the original 'query'.
query 是一個不透明的對象。它表示查詢的內部構造,不屬於公開的API。然而,這裏講到的Pickle 和Unpickle 這個屬性的內容是安全的(和徹底支持的)。
不能夠在不一樣版本之間共享Pickle 的結果
查詢集的Pickle 只能用於生成它們的Django 版本中。若是你使用Django 的版本N 生成一個Pickle,不保證這個Pickle 在Django 的版本N+1 中能夠讀取。Pickle 不可用於歸檔的長期策略。
New in Django 1.8.
由於Pickle 兼容性的錯誤很難診斷例如產生損壞的對象,當你試圖Unpickle 的查詢集與Pickle 時的Django 版本不一樣,將引起一個RuntimeWarning。
下面是對於查詢集的正式定義:
class QuerySet([model=None, query=None, using=None])[source]
一般你在使用QuerySet時會以鏈式的filter 來使用。爲了讓這個能工做,大部分QuerySet 方法返回新的QuerySet。這些方法在本節將詳細講述。
QuerySet 類具備兩個公有屬性用於內省:
ordered[source]
若是QuerySet 是排好序的則爲True —— 例若有一個order_by() 子句或者模型有默認的排序。不然爲False .
db[source]
若是如今執行,則返回將使用的數據庫。
注
QuerySet 存在query 參數是爲了讓具備特殊查詢用途的子類如GeoQuerySet 能夠從新構造內部的查詢狀態。這個參數的值是查詢狀態的不透明的表示,不是一個公開的API。簡而言之:若是你有疑問,那麼你實際上不須要使用它。
Django 提供了一系列 的QuerySet篩選方法,用於改變 QuerySet 返回的結果類型或者SQL查詢執行的方式。
filter(**kwargs)
返回一個新的QuerySet,包含與給定的查詢參數匹配的對象。
查找的參數(**kwargs)應該知足下文字段查找中的格式。在底層的SQL 語句中,多個參數經過AND 鏈接。
若是你須要執行更復雜的查詢(例如,使用OR 語句查詢),你可使用Q 對象。
exclude(**kwargs)
返回一個新的QuerySet,它包含不知足給定的查找參數的對象。
查找的參數(**kwargs)應該知足下文字段查找中的格式。 在底層的SQL 語句中,多個參數經過AND 鏈接,而後全部的內容放入NOT() 中。
下面的示例排除全部pub_date 晚於2005-1-3 且headline 爲「Hello」 的記錄:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')
用SQL 語句,它等同於:
SELECT ... WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')
下面的示例排除全部pub_date 晚於2005-1-3 或者headline 爲「Hello」 的記錄:
Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')
用SQL 語句,它等同於:
SELECT ... WHERE NOT pub_date > '2005-1-3' AND NOT headline = 'Hello'
注意,第二個示例更嚴格。
若是你須要執行更復雜的查詢(例如,使用OR 語句查詢),你可使用Q 對象。
annotate(*args, **kwargs)
使用提供的查詢表達式Annotate 查詢集中的每一個對象。查詢表達式能夠是一個簡單的值、模型(或關聯模型)字段的一個引用或對查詢集中的對象一個聚合函數(平均值、和等)。
New in Django 1.8:
以前版本的Django 值容許聚合函數用做Annotation。如今可使用各類表達式annotate 一個模型。
annotate() 的每一個參數都是一個annotation,它將添加到返回的QuerySet 中每一個對象。
Django 提供的聚合函數在下文的聚合函數文檔中講述。
關鍵字參數指定的Annotation 將使用關鍵字做爲Annotation 的別名。匿名的參數的別名將基於聚合函數的名稱和模型的字段生成。只有引用單個字段的聚合表達式纔可使用匿名參數。其它全部形式都必須用關鍵字參數。
例如,若是你正在操做一個Blog 列表,你可能想知道每一個Blog 有多少Entry:
>>> from django.db.models import Count >>> q = Blog.objects.annotate(Count('entry')) # The name of the first blog >>> q[0].name 'Blogasaurus' # The number of entries on the first blog >>> q[0].entry__count 42
Blog 模型自己沒有定義entry__count 屬性,可是經過使用一個關鍵字參數來指定聚合函數,你能夠控制Annotation 的名稱:
>>> q = Blog.objects.annotate(number_of_entries=Count('entry')) # The number of entries on the first blog, using the name provided >>> q[0].number_of_entries 42
聚合的深刻討論,參見 聚合主題的指南。
order_by(*fields)
默認狀況下,QuerySet 根據模型Meta 類的ordering 選項排序。你可使用order_by 方法給每一個QuerySet 指定特定的排序。
例如:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')
上面的結果將按照pub_date 降序排序,而後再按照headline 升序排序。"-pub_date" 前面的負號表示降序排序。隱式的是升序排序。若要隨機排序,請使用"?",像這樣:
Entry.objects.order_by('?')
注:order_by('?') 查詢可能耗費資源且很慢,這取決於使用的數據庫。
若要按照另一個模型中的字段排序,可使用查詢關聯模型時的語法。即經過字段的名稱後面跟上兩個下劃線(__),再跟上新模型中的字段的名稱,直至你但願鏈接的模型。例如:
Entry.objects.order_by('blog__name', 'headline')
若是排序的字段與另一個模型關聯,Django 將使用關聯的模型的默認排序,或者若是沒有指定Meta.ordering 將經過關聯的模型的主鍵排序。 例如,由於Blog 模型沒有指定默認的排序:
Entry.objects.order_by('blog') ... 等同於: Entry.objects.order_by('blog__id')
若是Blog 設置ordering = ['name'],那麼第一個QuerySet 將等同於:
Entry.objects.order_by('blog__name')
經過關聯字段排序QuerySet 還可以不用帶來JOIN 產生的花費,方法是引用關聯字段的_id:
# No Join Entry.objects.order_by('blog_id') # Join Entry.objects.order_by('blog__id')
New in Django 1.7:
QuerySet 經過關聯字段進行排序不用帶來JOIN 產生的開銷。
你還能夠經過調用表達式的asc() 或者desc(),根據查詢表達式排序:
Entry.objects.order_by(Coalesce('summary', 'headline').desc())
New in Django 1.8:
增長根據查詢表達式排序。
若是你還用到distinct(),在根據關聯模型中的字段排序時要當心。distinct() 中有一個備註講述關聯模型的排序如何對結果產生影響。
注
指定一個多值字段來排序結果(例如,一個ManyToManyField 字段或者ForeignKey 字段的反向關聯)。
考慮下面的狀況:
class Event(Model): parent = models.ForeignKey('self', related_name='children') date = models.DateField() Event.objects.order_by('children__date')
這裏,每一個Event 可能有多個潛在的排序數據;換句話說, 用 order_by()方法對 QuerySet對象進行操做會返回一個擴大版的新QuerySet對象——新增的條目也許並無什麼卵用,你也用不着它們。
所以,當你使用多值字段對結果進行排序時要格外當心。
沒有方法指定排序是否考慮大小寫。對於大小寫的敏感性,Django 將根據數據庫中的排序方式排序結果。
你能夠經過Lower將一個字段轉換爲小寫來排序,它將達到大小寫一致的排序:
Entry.objects.order_by(Lower('headline').desc())
New in Django 1.8:
新增根據表達式如Lower 來排序。
若是你不想對查詢作任何排序,即便是默認的排序,能夠不帶參數調用order_by()。
你能夠經過檢查QuerySet.ordered 屬性來知道查詢是不是排序的,若是QuerySet 有任何方式的排序它將爲True。
每一個order_by() 都將清除前面的任何排序。例如,下面的查詢將按照pub_date 排序,而不是headline:
Entry.objects.order_by('headline').order_by('pub_date')
警告
排序不是沒有開銷的操做。添加到排序中的每一個字段都將帶來數據庫的開銷。添加的每一個外鍵也都將隱式包含進它的默認排序。
reverse()
reverse() 方法反向排序QuerySet 中返回的元素。第二次調用reverse() 將恢復到原有的排序。
如要獲取QuerySet 中最後五個元素,你能夠這樣作:
my_queryset.reverse()[:5]
注意,這與Python 中從一個序列的末尾進行切片有點不同。上面的例子將首先返回最後一個元素,而後是倒數第二個元素,以此類推。若是咱們有一個Python 序列,當咱們查看seq[-5:] 時,咱們將一會兒獲得倒數五個元素。Django 不支持這種訪問模型(從末尾進行切片),由於它不可能利用SQL 高效地實現。
同時還要注意,reverse() 應該只在一個已經定義排序的QuerySet 上調用(例如,在一個定義了默認排序的模型上,或者使用order_by() 的時候)。若是QuerySet 沒有定義排序,調用reverse() 將不會有任何效果(在調用reverse() 以前沒有定義排序,那麼調用以後仍保持沒有定義)。
distinct([*fields])
返回一個在SQL 查詢中使用SELECT DISTINCT 的新QuerySet。它將去除查詢結果中重複的行。
默認狀況下,QuerySet 不會去除重複的行。在實際應用中,這通常不是個問題,由於像Blog.objects.all() 這樣的簡單查詢不會引入重複的行。可是,若是查詢跨越多張表,當對QuerySet 求值時就可能獲得重複的結果。這時候你應該使用distinct()。
注
order_by() 調用中的任何字段都將包含在SQL 的 SELECT 列中。與distinct() 一塊兒使用時可能致使預計不到的結果。若是你根據關聯模型的字段排序,這些fields將添加到查詢的字段中,它們可能產生本應該是惟一的重複的行。由於多餘的列沒有出如今返回的結果中(它們只是爲了支持排序),有時候看上去像是返回了不明確的結果。
示例(除第一個示例外,其餘示例都只能在PostgreSQL 上工做):
>>> Author.objects.distinct() [...] >>> Entry.objects.order_by('pub_date').distinct('pub_date') [...] >>> Entry.objects.order_by('blog').distinct('blog') [...] >>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date') [...] >>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date') [...] >>> Entry.objects.order_by('author', 'pub_date').distinct('author') [...]
values(*fields)
返回一個ValuesQuerySet —— QuerySet 的一個子類,迭代時返回字典而不是模型實例對象。
每一個字典表示一個對象,鍵對應於模型對象的屬性名稱。
下面的例子將values() 與普通的模型對象進行比較:
# This list contains a Blog object. >>> Blog.objects.filter(name__startswith='Beatles') [<Blog: Beatles Blog>] # This list contains a dictionary. >>> Blog.objects.filter(name__startswith='Beatles').values() [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]
values() 接收可選的位置參數*fields,它指定SELECT 應該限制哪些字段。若是指定字段,每一個字典將只包含指定的字段的鍵/值。若是沒有指定字段,每一個字典將包含數據庫表中全部字段的鍵和值。
例如:
>>> Blog.objects.values() [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}], >>> Blog.objects.values('id', 'name') [{'id': 1, 'name': 'Beatles Blog'}]
值得注意的幾點:
若是你有一個字段foo 是一個ForeignKey,默認的values() 調用返回的字典將有一個叫作foo_id 的鍵,由於這是保存實際的值的那個隱藏的模型屬性的名稱(foo 屬性引用關聯的模型)。當你調用values() 並傳遞字段的名稱,傳遞foo 或foo_id 均可以,獲得的結果是相同的(字典的鍵會與你傳遞的字段名匹配)。
例如:
>>> Entry.objects.values() [{'blog_id': 1, 'headline': 'First Entry', ...}, ...] >>> Entry.objects.values('blog') [{'blog': 1}, ...] >>> Entry.objects.values('blog_id') [{'blog_id': 1}, ...]
當values() 與distinct() 一塊兒使用時,注意排序可能影響最終的結果。詳細信息參見distinct() 中的備註。
若是values() 子句位於extra() 調用以後,extra() 中的select 參數定義的字段必須顯式包含在values() 調用中。values() 調用後面的extra() 調用將忽略選擇的額外的字段。
在values() 以後調用only() 和defer() 不太合理,因此將引起一個NotImplementedError。
New in Django 1.7:
新增最後一點。之前,在values() 以後調用only() 和defer() 是容許的,可是它要麼會崩潰要麼返回錯誤的結果。
ValuesQuerySet 用於你知道你只須要字段的一小部分,而不須要用到模型實例對象的函數。只選擇用到的字段固然更高效。
最後,要注意ValuesQuerySet 是QuerySet 的子類,它實現了大部分相同的方法。你能夠對它調用filter()、order_by() 等等。這表示下面的兩個調用徹底相同:
Blog.objects.values().order_by('id') Blog.objects.order_by('id').values()
Django 的做者喜歡將影響SQL 的方法放在前面,而後放置影響輸出的方法(例如values()),可是實際上無所謂。這是賣弄你個性的好機會。
你能夠經過OneToOneField、ForeignKey 和 ManyToManyField 屬性反向引用關聯的模型的字段:
Blog.objects.values('name', 'entry__headline') [{'name': 'My blog', 'entry__headline': 'An entry'}, {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]
警告
由於ManyToManyField 字段和反向關聯可能有多個關聯的行,包含它們可能致使結果集的倍數放大。若是你在values() 查詢中包含多個這樣的字段將更加明顯,這種狀況下將返回全部可能的組合。
values_list(*fields, flat=False)
與values() 相似,只是在迭代時返回的是元組而不是字典。每一個元組包含傳遞給values_list() 調用的字段的值 —— 因此第一個元素爲第一個字段,以此類推。例如:
>>> Entry.objects.values_list('id', 'headline') [(1, 'First entry'), ...]
若是隻傳遞一個字段,你還能夠傳遞flat 參數。若是爲True,它表示返回的結果爲單個值而不是元組。一個例子會讓它們的區別更加清晰:
>>> Entry.objects.values_list('id').order_by('id') [(1,), (2,), (3,), ...] >>> Entry.objects.values_list('id', flat=True).order_by('id') [1, 2, 3, ...]
若是有多個字段,傳遞flat 將發生錯誤。
若是你不傳遞任何值給values_list(),它將返回模型中的全部字段,以它們在模型中定義的順序。
注意,這個方法返回ValuesListQuerySet。這個類的行爲相似列表。大部分時候它足夠用了,可是若是你須要一個真實的Python 列表對象,能夠對它調用list(),這將會對查詢集求值。
dates(field, kind, order='ASC')
返回一個 DateQuerySet ,就是提取 QuerySet 查詢中所包含的日期,將其組成一個新的 datetime.datetime 對象的列表。
field 是你的 model 中的 DateField 或 DateTimeField 字段名稱。
kind 是 "year", "month" 或 "day" 之一。 每一個 datetime.datetime 對象都會根據所給的 type 進行截減。
order, 默認是 'ASC',只有兩個取值 'ASC' 或 'DESC'。它決定結果如何排序。
例如:
>>> Entry.objects.dates('pub_date', 'year') [datetime.date(2005, 1, 1)] >>> Entry.objects.dates('pub_date', 'month') [datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)] >>> Entry.objects.dates('pub_date', 'day') [datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)] >>> Entry.objects.dates('pub_date', 'day', order='DESC') [datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)] >>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day') [datetime.date(2005, 3, 20)]
datetimes(field_name, kind, order='ASC', tzinfo=None)
返回一個QuerySet 就是提取 QuerySet 查詢中所包含的時間,相似dates。
none() 返回一個 EmptyQuerySet -- 它是一個運行時只返回空列表的 QuerySet。它常常用在這種場合:你要返回一個空列表,可是調用者卻須要接收一個 QuerySet 對象。(這時,就能夠用它代替空列表)
Examples:
>>> Entry.objects.none() [] >>> from django.db.models.query import EmptyQuerySet >>> isinstance(Entry.objects.none(), EmptyQuerySet) True
all()
返回當前QuerySet(或QuerySet 子類) 的副本。它能夠用於在你但願傳遞一個模型管理器或QuerySet 並對結果作進一步過濾的狀況。無論對哪種對象調用all(),你都將得到一個能夠工做的QuerySet。
當對QuerySet進行求值時,它一般會緩存其結果。若是數據庫中的數據在QuerySet求值以後可能已經改變,你能夠經過在之前求值過的QuerySet上調用相同的all() 查詢以得到更新後的結果。
select_related(*fields)
返回一個QuerySet,當執行它的查詢時它沿着外鍵關係查詢關聯的對象的數據。它會生成一個複雜的查詢並引發性能的損耗,可是在之後使用外鍵關係時將不須要數據庫查詢。
下面的例子解釋了普通查詢和select_related() 查詢的區別。下面是一個標準的查詢:
# Hits the database. e = Entry.objects.get(id=5) # Hits the database again to get the related Blog object. b = e.blog
下面是一個select_related 查詢:
# Hits the database. e = Entry.objects.select_related('blog').get(id=5) # Doesn't hit the database, because e.blog has been prepopulated # in the previous query. b = e.blog
select_related() 可用於任何對象的查詢集:
from django.utils import timezone # Find all the blogs with entries scheduled to be published in the future. blogs = set() for e in Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog'): # Without select_related(), this would make a database query for each # loop iteration in order to fetch the related blog for each entry. blogs.add(e.blog)
filter() 和select_related() 鏈的順序不重要。下面的查詢集是等同的:
Entry.objects.filter(pub_date__gt=timezone.now()).select_related('blog') Entry.objects.select_related('blog').filter(pub_date__gt=timezone.now())
你能夠沿着外鍵查詢。若是你有如下模型:
from django.db import models class City(models.Model): # ... pass class Person(models.Model): # ... hometown = models.ForeignKey(City) class Book(models.Model): # ... author = models.ForeignKey(Person)
... 那麼Book.objects.select_related('author__hometown').get(id=4) 調用將緩存關聯的Person 和關聯的 City:
b = Book.objects.select_related('author__hometown').get(id=4) p = b.author # Doesn't hit the database. c = p.hometown # Doesn't hit the database. b = Book.objects.get(id=4) # No select_related() in this example. p = b.author # Hits the database. c = p.hometown # Hits the database.
在傳遞給select_related() 的字段中,你可使用任何ForeignKey 和OneToOneField。
在傳遞給select_related 的字段中,你還能夠反向引用OneToOneField —— 也就是說,你能夠回溯到定義OneToOneField 的字段。此時,可使用關聯對象字段的related_name,而不要指定字段的名稱。
有些狀況下,你但願對不少對象調用select_related(),或者你不知道全部的關聯關係。在這些狀況下,能夠調用不帶參數的select_related()。它將查找能找到的全部不可爲空外鍵 —— 能夠爲空的外鍵必須明確指定。大部分狀況下不建議這樣作,由於它會使得底層的查詢很是複雜而且返回的不少數據都不是真實須要的。
若是你須要清除QuerySet 上之前的select_related 添加的關聯字段,能夠傳遞一個None 做爲參數:
>>> without_relations = queryset.select_related(None)
鏈式調用select_related 的工做方式與其它方法相似 —— 也就是說,select_related('foo', 'bar') 等同於select_related('foo').select_related('bar')。
Changed in Django 1.7:
在之前,後者等同於select_related('bar')。
對於多對多字段(ManyToManyField)和一對多字段,可使用prefetch_related()來進行優化。或許你會說,沒有一個叫OneToManyField的東西啊。實際上 ,ForeignKey就是一個多對一的字段,而被ForeignKey關聯的字段就是一對多字段了。
做用和方法
prefetch_related()和select_related()的設計目的很類似,都是爲了減小SQL查詢的數量,可是實現的方式不同。後者是經過JOIN語句,在SQL查詢內解決問題。可是對於多對多關係,使用SQL語句解決就顯得有些不太明智,由於JOIN獲得的表將會很長,會致使SQL語句運行時間的增長和內存佔用的增長。如有n個對象,每一個對象的多對多字段對應Mi條,就會生成Σ(n)Mi 行的結果表。
prefetch_related()的解決方法是,分別查詢每一個表,而後用Python處理他們之間的關係。
例如:
from django.db import models class Topping(models.Model): name = models.CharField(max_length=30) class Pizza(models.Model): name = models.CharField(max_length=50) toppings = models.ManyToManyField(Topping) def __str__(self): # __unicode__ on Python 2 return "%s (%s)" % (self.name, ", ".join(topping.name for topping in self.toppings.all())) and run: >>> Pizza.objects.all() ["Hawaiian (ham, pineapple)", "Seafood (prawns, smoked salmon)"...
extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
有些狀況下,Django的查詢語法難以簡單的表達複雜的 WHERE 子句,對於這種狀況, Django 提供了 extra() QuerySet 修改機制 — 它能在 QuerySet生成的SQL從句中注入新子句
Warning
不管什麼時候你都須要很是當心的使用extra().
因爲產品差別的緣由,這些自定義的查詢難以保障在不一樣的數據庫之間兼容(由於你手寫 SQL 代碼的緣由),並且違背了 DRY 原則,因此如非必要,仍是儘可能避免寫 extra。
extra能夠指定一個或多個 參數,例如 select, where or tables. 這些參數都不是必須的,可是你至少要使用一個select。The select 參數可讓你在 SELECT 從句中添加其餘字段信息,它應該是一個字典,存放着屬性名到 SQL 從句的映射。
Example:
Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
結果集中每一個 Entry 對象都有一個額外的屬性is_recent, 它是一個布爾值,表示 Entry對象的pub_date 是否晚於 Jan. 1, 2006.
Django 會直接在 SELECT 中加入對應的 SQL 片段,因此轉換後的 SQL 以下:
SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent FROM blog_entry;
下面這個例子更復雜一些;它會在每一個 Blog對象中添加一個 entry_count 屬性,它會運行一個子查詢,獲得相關聯的 Entry 對象的數量:
Blog.objects.extra( select={ 'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id' }, )
在上面這個特例中,咱們要了解這個事實,就是 blog_blog 表已經存在於FROM從句中
上面的查詢相似下面sql語句:
SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count FROM blog_blog;
要注意的是,大多數數據庫須要在子句兩端添加括號,而在 Django 的select從句中卻無須這樣。
例如:
Blog.objects.extra( select=OrderedDict([('a', '%s'), ('b', '%s')]), select_params=('one', 'two'))
defer(*fields)
在某些數據複雜的環境下,你的 model 可能包含很是多的字段,可能某些字段包含很是多的數據(好比,文檔字段),或者將其轉化爲 Python 對象會消耗很是多的資源。在這種狀況下,有時你可能並不須要這種字段的信息,那麼你可讓 Django 不讀取它們的數據。
將不想載入的字段的名稱傳給 defer() 方法,就能夠作到延後載入:
Entry.objects.defer("lede", "body")
延後截入字段的查詢返回的還是 model 類的實例。在你訪問延後載入字段時,你仍能夠得到字段的內容,所不一樣的是,內容是在你訪問延後字段時纔讀取數據庫的,而普通字段是在運行查詢(queryset)時就一次性從數據庫中讀取數據的。
你能夠屢次調用 defer() 方法。每一個調用均可以添加新的延後載入字段:
# Defers both the body and lede fields. Entry.objects.defer("body").filter(headline="Lennon").defer("lede")
對延後載入字段進行排序是不會起做用的;重複添加延後載入字段也不會有何不良影響。
你也能夠延後載入關聯 model 中的字段(前提是你使用 select_related() 載入了關聯 model),用法也是用雙下劃線鏈接關聯字段:
Blog.objects.select_related().defer("entry__lede", "entry__body")
若是你想清除延後載入的設置,只要使用將 None 作爲參數傳給 defer() 便可:
# Load all fields immediately. my_queryset.defer(None)
有些字段不管你如何指定,都不會被延後加載。好比,你永遠不能延後加載主鍵字段。若是你使用 select_related() 得到關聯 model 字段信息,那麼你就不能延後載入關聯 model 的主鍵。(若是這樣作了,雖然不會拋出錯誤,事實上卻不完成延後加載)
注意
defer() 方法(和隨後提到的 only() 方法) 都只適用於特定狀況下的高級屬性。它們能夠提供性能上的優化,不過前提是你已經對你用到的查詢有過很深刻細緻的分析,很是清楚你須要的到底是哪些信息,並且已經對你所須要的數據和默認狀況下返回的全部數據進行比對,清楚二者之間的差別。這完成了上述工做以後,再使用這兩種方法進行優化纔是有意義的。因此當你剛開始構建你的應用時,先不要急着使用 defer() 方法,等你已經寫完查詢而且分析成哪些方面是熱點應用之後,再用也不遲。
only(*fields)
only() 方法或多或少與 defer() 的做用相反。若是你在提取數據時但願某個字段不該該被延後載入,而應該當即載入,那麼你就能夠作使用 only() 方法。若是你一個 model ,你但願它全部的字段都延後加載,只有某幾個字段是當即載入的,那麼你就應該使用 only() 方法。
若是你有一個 model,它有 name, age 和 biography 三個字段,那麼下面兩種寫法效果同樣的:
Person.objects.defer("age", "biography") Person.objects.only("name")
你不管什麼時候調用 only(),它都會馬上更改載入設置。這與它的命名很是相符:只有 only 中的字段會當即載入,而其餘的則都是延後載入的。所以,連續調用 only() 時,只有最後一個 only 方法纔會生效:
# This will defer all fields except the headline. Entry.objects.only("body", "lede").only("headline")
因爲 defer() 能夠遞增(每次都添加字段到延後載入的列表中),因此你能夠將 only() 和 defer() 結合在一塊兒使用,請注意使用順序,先 only 然後 defer:
# Final result is that everything except "headline" is deferred. Entry.objects.only("headline", "body").defer("body") # Final result loads headline and body immediately (only() replaces any # existing set of fields). Entry.objects.defer("body").only("headline", "body")
using(alias)
若是你使用多個數據庫,這個方法用於控制QuerySet 將在哪一個數據庫上求值。這個方法的惟一參數是數據庫的別名,定義在DATABASES。
例如:
# queries the database with the 'default' alias. >>> Entry.objects.all() # queries the database with the 'backup' alias >>> Entry.objects.using('backup')
select_for_update(nowait=False)
返回一個 queryset ,會鎖定相關行直到事務結束。在支持的數據庫上面產生一個SELECT ... FOR UPDATE 語句
例如:
entries = Entry.objects.select_for_update().filter(author=request.user)
全部匹配的行將被鎖定,直到事務結束。這意味着能夠經過鎖防止數據被其它事務修改。
通常狀況下若是其餘事務鎖定了相關行,那麼本查詢將被阻塞,直到鎖被釋放。若是這不是你想要的行爲,請使用select_for_update(nowait=True). 這將使查詢不阻塞。若是其它事務持有衝突的鎖, 那麼查詢將引起 DatabaseError 異常.
目前 postgresql_psycopg2, oracle 和 mysql 數據庫後端 select_for_update(). 可是 MySQL 不支持 nowait 參數。顯然,用戶應該檢查後端的支持狀況。
當在不支持nowait功能的數據庫後端(例如 MySql) 使用nowait=True 參數調用 select_for_update() 時將引起 DatabaseError 異常. 這是防止意外形成代碼被阻塞。
在自動提交模式下使用 select_for_update() 將引起 TransactionManagementError 異常,緣由是自動提交模式下不支持鎖定行。若是容許這個調用,那麼可能形成數據損壞,並且這個功能很容易在事務外被調用。
對於不支持 SELECT ... FOR UPDATE 的後端 (例如SQLite) select_for_update() 將沒有效果。
raw(raw_query, params=None, translations=None)
Changed in Django 1.7:
raw 移動到QuerySet 類中。之前,它只位於Manager 中。
接收一個原始的SQL 查詢,執行它並返回一個django.db.models.query.RawQuerySet 實例。這個RawQuerySet 實例能夠迭代以提供實例對象,就像普通的QuerySet 同樣。
更多信息參見執行原始的SQL 查詢。
警告
raw() 永遠觸發一個新的查詢,而與以前的filter 無關。所以,它一般應該從Manager 或一個全新的QuerySet 實例調用。
這些方法每次被調用的時候都會查詢數據庫。
get(**kwargs)
返回按照查詢參數匹配到的對象,參數的格式應該符合 Field lookups的要求.
若是匹配到的對象個數不僅一個的話,get() 將會觸發MultipleObjectsReturned 異常. MultipleObjectsReturned 異常是模型類的屬性.
若是根據給出的參數匹配不到對象的話,get() 將觸發DoesNotExist 異常. 這個異常是模型類的屬性. Example:
Entry.objects.get(id='foo') # raises Entry.DoesNotExist The DoesNotExist exception inherits from django.core.exceptions.ObjectDoesNotExist, so you can target multiple DoesNotExist exceptions. Example: from django.core.exceptions import ObjectDoesNotExist try: e = Entry.objects.get(id=3) b = Blog.objects.get(id=1) except ObjectDoesNotExist: print("Either the entry or blog doesn't exist.")
create(**kwargs)
一個在一步操做中同時建立對象而且保存的便捷方法. 因此:
p = Person.objects.create(first_name="Bruce", last_name="Springsteen")和:p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)
是等同的.
參數 force_insert 在其餘的文檔中有介紹, 它意味着一個新的對象必定會被建立. 正常狀況中,你沒必要要擔憂這點. 然而, 若是你的model中有一個你手動設置主鍵, 而且這個值已經存在於數據庫中, 調用 create()將會失敗而且觸發 IntegrityError 由於主鍵必須是惟一的. 若是你手動設置了主鍵,作好異常處理的準備.
get_or_create(defaults=None, **kwargs)
一個經過給出的kwargs 來查詢對象的便捷方法(若是你的模型中的全部字段都有默認值,能夠爲空),須要的話建立一個對象。
返回一個由(object, created)組成的元組,元組中的object 是一個查詢到的或者是被建立的對象, created 是一個表示是否建立了新的對象的布爾值。
這主要用做樣板代碼的一種快捷方式。例如:
try: obj = Person.objects.get(first_name='John', last_name='Lennon') except Person.DoesNotExist: obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9)) obj.save()
若是模型的字段數量較大的話,這種模式就變的很是不易用了。上面的示例能夠用get_or_create()重寫 :
obj, created = Person.objects.get_or_create(first_name='John', last_name='Lennon', defaults={'birthday': date(1940, 10, 9)})
任何傳遞給 get_or_create() 的關鍵字參數,除了一個可選的defaults,都將傳遞給get() 調用。若是查找到一個對象,get_or_create() 返回一個包含匹配到的對象以及False 組成的元組。若是查找到的對象超過一個以上,get_or_create 將引起MultipleObjectsReturned。若是查找不到對象, get_or_create() 將會實例化並保存一個新的對象,返回一個由新的對象以及True 組成的元組。新的對象將會大概按照如下的邏輯建立:
params = {k: v for k, v in kwargs.items() if '__' not in k} params.update(defaults) obj = self.model(**params) obj.save()
它表示從非'defaults' 且不包含雙下劃線的關鍵字參數開始(暗示這是一個不精確的查詢)。而後將defaults 的內容添加進來,覆蓋必要的鍵,並使用結果做爲關鍵字參數傳遞給模型類。這是對用到的算法的簡單描述,但它包含了全部的相關的細節。內部的實現有更多的錯誤檢查並處理一些邊緣條件;若是感興趣,請閱讀代碼。
若是你有一個名爲defaults的字段,而且想在get_or_create() 是用它做爲精確查詢,只須要使用'defaults__exact',像這樣:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
當你使用手動指定的主鍵時,get_or_create() 方法與create()方法有類似的錯誤行爲 。若是須要建立一個對象而該對象的主鍵早已存在於數據庫中,IntegrityError 異常將會被觸發。
這個方法假設正確使用原子操做,正確的數據庫配置和底層數據庫的正確行爲。然而,若是數據庫級別沒有對get_or_create 中用到的kwargs 強制要求惟一性(參見unique 和 unique_together),這個方法容易致使競態條件可能會仍具備相同參數的多行同時插入。
若是你正在使用MySQL,請確保使用READ COMMITTED 隔離級別而不是默認的REPEATABLE READ,不然你將會遇到get_or_create 引起IntegrityError 但對象在接下來的get() 調用中並不存在的狀況。
最後講一句get_or_create() 在Django 視圖中的使用。請確保只在POST 請求中使用,除非你有充分的理由。GET 請求不該該對數據有任何影響。而POST 則用於對數據產生影響的請求。更多信息,參見HTTP 細則中的安全的方法。
警告
你能夠經過ManyToManyField 屬性和反向關聯使用get_or_create()。在這種狀況下,你應該限制查詢在關聯的上下文內部。若是你不一致地使用它,將可能致使完整性問題。
根據下面的模型:
class Chapter(models.Model): title = models.CharField(max_length=255, unique=True) class Book(models.Model): title = models.CharField(max_length=256) chapters = models.ManyToManyField(Chapter)
你能夠經過Book 的chapters 字段使用get_or_create(),可是它只會獲取該Book 內部的上下文:
>>> book = Book.objects.create(title="Ulysses") >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, True) >>> book.chapters.get_or_create(title="Telemachus") (<Chapter: Telemachus>, False) >>> Chapter.objects.create(title="Chapter 1") <Chapter: Chapter 1> >>> book.chapters.get_or_create(title="Chapter 1") # Raises IntegrityError
發生這個錯誤時由於它嘗試經過Book 「Ulysses」 獲取或者建立「Chapter 1」,可是它不能:關聯關係不能獲取這個chapter 由於它與這個book 不關聯,但由於title 字段是惟一的它仍然不能建立。
update_or_create(defaults=None, **kwargs)
New in Django 1.7.
一個經過給出的kwargs 來更新對象的便捷方法, 若是須要的話建立一個新的對象。defaults 是一個由 (field, value) 對組成的字典,用於更新對象。
返回一個由 (object, created)組成的元組,元組中的object 是一個建立的或者是被更新的對象, created 是一個標示是否建立了新的對象的布爾值。
update_or_create 方法嘗試經過給出的kwargs 去從數據庫中獲取匹配的對象。若是找到匹配的對象,它將會依據defaults 字典給出的值更新字段。
這用做樣板代碼的一種快捷方式。例如:
try: obj = Person.objects.get(first_name='John', last_name='Lennon') for key, value in updated_values.iteritems(): setattr(obj, key, value) obj.save() except Person.DoesNotExist: updated_values.update({'first_name': 'John', 'last_name': 'Lennon'}) obj = Person(**updated_values) obj.save()
若是模型的字段數量較大的話,這種模式就變的很是不易用。上面的示例能夠用 update_or_create() 重寫:
obj, created = Person.objects.update_or_create( first_name='John', last_name='Lennon', defaults=updated_values)
kwargs 中的名稱如何解析的詳細描述能夠參見get_or_create()。
和上文描述的get_or_create() 同樣,這個方式容易致使競態條件,若是數據庫層級沒有前置惟一性它會讓多行同時插入。
bulk_create(objs, batch_size=None)
使用django orm大批量插入的時候咱們能夠不使用for循環對一個一個的save而是使用
bulk_create來批量插入
例如:
>>> Entry.objects.bulk_create([ ... Entry(headline="Django 1.0 Released"), ... Entry(headline="Django 1.1 Announced"), ... Entry(headline="Breaking: Django is awesome") ... ])
count()
返回在數據庫中對應的 QuerySet.對象的個數。 count() 永遠不會引起異常。
Example:
# Returns the total number of entries in the database. Entry.objects.count() # Returns the number of entries whose headline contains 'Lennon' Entry.objects.filter(headline__contains='Lennon').count()
接收一個主鍵值列表,而後根據每一個主鍵值所其對應的對象,返回一個主鍵值與對象的映射字典。
例如:
>>> Blog.objects.in_bulk([1]) {1: <Blog: Beatles Blog>} >>> Blog.objects.in_bulk([1, 2]) {1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>} >>> Blog.objects.in_bulk([]) {}
若是你給 in_bulk() 傳遞的是一個空列代表,獲得就是一個空字典。
iterator()
運行查詢(QuerySet),而後根據結果返回一個 迭代器(iterator。 作爲比較,使用 QuerySet 時,從數據庫中讀取全部記錄後,一次性將全部記錄實例化爲對應的對象;而 iterator() 則是讀取記錄後,是分屢次對數據實例化,用到哪一個對象才實例化哪一個對象。相對於一次性返回不少對象的 QuerySet,使用迭代器不只效率更高,並且更節省內存。
要注意的是,若是將 iterator() 做用於 QuerySet,那就意味着會再一次運行查詢,就是說會運行兩次查詢。
latest(field_name=None)
根據時間字段 field_name 獲得最新的對象。
下面這個例子根據 pub_date 字段獲得數據表中最新的 Entry 對象:
Entry.objects.latest('pub_date')
若是你在 model 中 Meta 定義了 get_latest_by 項, 那麼你能夠略去 field_name 參數。Django 會將 get_latest_by 作爲默認設置。
和 get(), latest() 同樣,若是根據所給條件沒有找到匹配的對象,就會拋出 DoesNotExist 異常。
注意 latest() 是純粹爲了易用易讀而存在的方法。
earliest(field_name=None)
一種相似latest()的查詢
first()
返回結果集的第一個對象, 當沒有找到時返回None.若是 QuerySet 沒有設置排序,則將會自動按主鍵進行排序
Example:
p = Article.objects.order_by('title', 'pub_date').first()
筆記:first() 是一個簡便方法 下面這個例子和上面的代碼效果是同樣
try: p = Article.objects.order_by('title', 'pub_date')[0] except IndexError: p = None
last()
工做方式相似first(),只是返回的是查詢集中最後一個對象。
aggregate(*args, **kwargs)
返回一個字典,包含根據QuerySet 計算獲得的聚合值(平均數、和等等)。aggregate() 的每一個參數指定返回的字典中將要包含的值。
Django 提供的聚合函數在下文的聚合函數中講述。由於聚合也是查詢表達式,你能夠組合多個聚合以及值來建立複雜的聚合。
使用關鍵字參數指定的聚合將使用關鍵字參數的名稱做爲Annotation 的名稱。匿名的參數的名稱將基於聚合函數的名稱和模型字段生成。複雜的聚合不可使用匿名參數,它們必須指定一個關鍵字參數做爲別名。
例如,當你使用Blog Entry 時,你可能想知道對Author 貢獻的Blog Entry 的數目:
>>> from django.db.models import Count >>> q = Blog.objects.aggregate(Count('entry')) {'entry__count': 16}
經過使用關鍵字參數來指定聚合函數,你能夠控制返回的聚合的值的名稱:
>>> q = Blog.objects.aggregate(number_of_entries=Count('entry')) {'number_of_entries': 16}
聚合的深刻討論,參見聚合的指南。
exists()
若是QuerySet 包含任何結果,則返回True,不然返回False。它會試圖用最簡單和最快的方法完成查詢,但它執行的方法與普通的QuerySet 查詢確實幾乎相同。
exists() 用於搜尋對象是否在QuerySet 中以及QuerySet 是否存在任何對象,特別是QuerySet 比較大的時候。
查找具備惟一性字段(例如primary_key)的模型是否在一個QuerySet 中的最高效的方法是:
entry = Entry.objects.get(pk=123) if some_queryset.filter(pk=entry.pk).exists(): print("Entry contained in queryset")
它將比下面的方法快不少,這個方法要求對QuerySet 求值並迭代整個QuerySet:
if entry in some_queryset: print("Entry contained in QuerySet")
若要查找一個QuerySet 是否包含任何元素:
if some_queryset.exists(): print("There is at least one object in some_queryset")
將快於:
if some_queryset: print("There is at least one object in some_queryset")
... 但不會快不少(由於這須要很大的QuerySet 以得到效率的提高)。
另外,若是some_queryset 尚未求值,但你知道它將在某個時刻求值,那麼使用some_queryset.exists() 將比簡單地使用bool(some_queryset) 完成更多的工做(一個查詢用於存在性檢查,另一個是後面的求值),後者將求值並檢查是否有結果返回。
update(**kwargs)
更新操做
例如:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
更新特定的數據
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
不能對外鍵進行更新操做
>>> Entry.objects.update(blog__name='foo') # Won't work!
能夠經過外鍵進行更新
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
下面是更新的變種方法
e = Entry.objects.get(id=10) e.comments_on = False e.save()
上面的語句相似下面的語句:
Entry.objects.filter(id=10).update(comments_on=False)
delete
delete()
刪除操做
例如:
>>> b = Blog.objects.get(pk=1)
刪除全部知足條件的
>>> Entry.objects.filter(blog=b).delete()
上面操做相似於下面語句:
blogs = Blog.objects.all() # This will delete all Blogs and all of their Entry objects. blogs.delete()
classmethod as_manager()
New in Django 1.7.
類方法返回一個管理器實例。
字段查詢是指如何指定SQL WHERE子句的內容. 它們經過查詢集的filter(), exclude() and get()的關鍵字參數指定.
精確匹配。
Examples:
Entry.objects.get(id__exact=14) Entry.objects.get(id__exact=None) SQL equivalents: SELECT ... WHERE id = 14; SELECT ... WHERE id IS NULL;
不區分大小寫的精確匹配
例如:
Blog.objects.get(name__iexact='beatles blog') Blog.objects.get(name__iexact=None) SQL equivalents: SELECT ... WHERE name ILIKE 'beatles blog'; SELECT ... WHERE name IS NULL;
模糊匹配.
例如:
Entry.objects.get(headline__contains='Lennon') SQL equivalent: SELECT ... WHERE headline LIKE '%Lennon%';
不區分大小寫的模糊匹配
例如:
Entry.objects.get(headline__icontains='Lennon') SQL equivalent: SELECT ... WHERE headline ILIKE '%Lennon%';
至關於數據庫的in查詢.
例如:
Entry.objects.filter(id__in=[1, 3, 4]) SQL equivalent: SELECT ... WHERE id IN (1, 3, 4);
你也能夠動態生成list進行in查詢:
inner_qs = Blog.objects.filter(name__contains='Cheddar') entries = Entry.objects.filter(blog__in=inner_qs)
上面的語句相似於下面的sql語句:
SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')
若是使用ValuesQuerySet 查詢,確保只選擇一個列:
inner_qs = Blog.objects.filter(name__contains='Ch').values('name') entries = Entry.objects.filter(blog__name__in=inner_qs)
這個例子將產生一個異常,因爲內查詢試圖提取兩個字段的值,可是查詢語句只指望提取一個字段的值:
# Bad code! Will raise a TypeError. inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id') entries = Entry.objects.filter(blog__name__in=inner_qs)
大於
例子:
Entry.objects.filter(id__gt=4) SQL語句至關於: SELECT ... WHERE id > 4;
大於或等於
小於
小於或等於
區分大小寫,開始位置匹配
例如:
Entry.objects.filter(headline__startswith='Will') SQL equivalent: SELECT ... WHERE headline LIKE 'Will%';
SQLite 不支持區分大小寫 LIKE 語句; Sqlite 下startswith 等於 istartswith .
不區分大小寫,開始位置匹配
例如:
Entry.objects.filter(headline__istartswith='will') SQL equivalent: SELECT ... WHERE headline ILIKE 'Will%';
以什麼結尾.
例如:
Entry.objects.filter(headline__endswith='cats') SQL equivalent: SELECT ... WHERE headline LIKE '%cats';
以什麼結尾不區分大小寫.
例如:
Entry.objects.filter(headline__iendswith='will') SQL equivalent: SELECT ... WHERE headline ILIKE '%will'
範圍查詢,相似於sql的between and.
Example:
import datetime start_date = datetime.date(2005, 1, 1) end_date = datetime.date(2005, 3, 31) Entry.objects.filter(pub_date__range=(start_date, end_date)) SQL equivalent: SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';
對日期/時間字段精確匹配年分,年分用四位數字表示。
例如:
Entry.objects.filter(pub_date__year=2005)
等價於 SQL:
SELECT ... WHERE EXTRACT('year' FROM pub_date) = '2005';
(不一樣的數據庫引擎中,翻譯獲得的 SQL 也不盡相同。)
對日期/時間字段精確匹配月分,用整數表示月分,好比 1 表示一月,12 表示十二月。
例如:
Entry.objects.filter(pub_date__month=12)
等價於 SQL:
SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
(不一樣的數據庫引擎中,翻譯獲得的 SQL 也不盡相同。)
對於日期和日期時間字段,具體到某一天的匹配。取一個整數的天數。
Example:
Entry.objects.filter(pub_date__day=3) SQL equivalent: SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
對日期/時間字段匹配星期幾
例如:
Entry.objects.filter(pub_date__week_day=2)
等價於 SQL:
SELECT ... WHERE EXTRACT('dow' FROM pub_date) = '2';
(不一樣的數據庫引擎中,翻譯獲得的 SQL 也不盡相同。)
要注意的是,這段代碼將獲得 pub_date 字段是星期一的全部記錄 (西方習慣於將星期一看作一週的次日),與它的年月信息無關。星期以星期天作爲第一天,以星期六作爲最後一天。
對於小時的匹配,取值只能是0到23之間.
例如:
Event.objects.filter(timestamp__hour=23) SQL equivalent: SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
對於分鐘的匹配,取值只能是0到59之間.
例如:
Event.objects.filter(timestamp__minute=29) SQL equivalent: SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
對於秒的匹配,取值只能是0到59之間.
例如:
Event.objects.filter(timestamp__second=31) 等同於SQL語句: SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
值爲 True 或 False, 至關於 SQL語句IS NULL和IS NOT NULL.
例如:
Entry.objects.filter(pub_date__isnull=True) SQL equivalent: SELECT ... WHERE pub_date IS NULL;
一個Boolean類型的全文搜索,以全文搜索的優點。這個很像 contains ,可是因爲全文索引的優點,以使它更顯著的快。
Example:
Entry.objects.filter(headline__search="+Django -jazz Python") SQL equivalent: SELECT ... WHERE MATCH(tablename, headline) AGAINST (+Django -jazz Python IN BOOLEAN MODE);
正則表達式的匹配規則
例如:
Entry.objects.get(title__regex=r'^(An?|The) +') SQL equivalents: SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'c'); -- Oracle SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite
正則表達式的匹配規則,忽略大小寫
例如:
Entry.objects.get(title__iregex=r'^(an?|the) +') SQL equivalents: SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite
Django 的django.db.models 模塊提供如下聚合函數。關於如何使用這些聚合函數的細節,參見聚合函數的指南。關於如何建立聚合函數,參數聚合函數 的文檔。
警告
SQLite 不能直接處理日期/時間字段的聚合。這是由於SQLite 中沒有原生的日期/時間字段,Django 目前使用文本字段模擬它的功能。在SQLite 中對日期/時間字段使用聚合將引起NotImplementedError。
注
在QuerySet 爲空時,聚合函數函數將返回None。 例如,若是QuerySet 中沒有記錄,Sum 聚合函數將返回None 而不是0。Count 是一個例外,若是QuerySet 爲空,它將返回0。
全部聚合函數具備如下共同的參數:
引用模型字段的一個字符串,或者一個查詢表達式。
New in Django 1.8:
如今在複雜的計算中,聚合函數能夠引用多個字段。
用來表示返回值的模型字段,它是一個可選的參數。
New in Django 1.8:
添加output_field 參數。
注
在組合多個類型的字段時,只有在全部的字段都是相同類型的狀況下,Django 才能肯定output_field。不然,你必須本身提供output_field 參數。
這些關鍵字參數能夠給聚合函數生成的SQL 提供額外的信息。
class Avg(expression, output_field=None, **extra)
返回給定expression 的平均值,其中expression 必須爲數值。
默認的別名:<field>__avg
返回類型:float
class Count(expression, distinct=False, **extra)
返回與expression 相關的對象的個數。
默認的別名:<field>__count
返回類型:int
有一個可選的參數:distinct 若是distinct=True,Count 將只計算惟一的實例。它等同於COUNT(DISTINCT <field>) SQL 語句。默認值爲False。
class Max(expression, output_field=None, **extra)
返回expression 的最大值。
默認的別名:<field>__max
返回類型:與輸入字段的類型相同,若是提供則爲 output_field 類型
class Min(expression, output_field=None, **extra)
返回expression 的最小值。
默認的別名:<field>__min
返回的類型:與輸入字段的類型相同,若是提供則爲 output_field 類型
class StdDev(expression, sample=False, **extra)
返回expression 的標準差。
默認的別名:<field>__stddev
返回類型:float
有一個可選的參數:
sample
默認狀況下,StdDev 返回羣體的標準差。可是,若是sample=True,返回的值將是樣本的標準差。
SQLite
SQLite 沒有直接提供StdDev。有一個可用的實現是SQLite 的一個擴展模塊。參見SQlite 的文檔 中獲取並安裝這個擴展的指南。
class Sum(expression, output_field=None, **extra)
計算expression 的全部值的和。
默認的別名:<field>__sum
返回類型:與輸入的字段相同,若是提供則爲output_field 的類型
class Variance(expression, sample=False, **extra)
返回expression 的方差。
默認的別名:<field>__variance
返回的類型:float
有一個可選的參數:sample 默認狀況下,Variance 返回羣體的方差。可是,若是sample=True,返回的值將是樣本的方差。
SQLite
SQLite 沒有直接提供Variance。有一個可用的實現是SQLite 的一個擴展模塊。 參見SQlite 的文檔 中獲取並安裝這個擴展的指南。
本節提供查詢相關的工具的參考資料,它們其它地方沒有文檔。
class Q
Q對象(django.db.models.Q)能夠對關鍵字參數進行封裝,從而更好地應用多個查詢。
通常咱們在Django程序中查詢數據庫操做都是在QuerySet裏進行進行,例以下面代碼:
>>> q1 = Entry.objects.filter(headline__startswith="What") >>> q2 = q1.exclude(pub_date__gte=datetime.date.today()) >>> q3 = q1.filter(pub_date__gte=datetime.date.today())
或者將其組合起來,例如:
>>>q1 = Entry.objects.filter(headline_startswith="What").exclude(pub_date_gte=datetime.date.today())
隨着咱們的程序愈來愈複雜,查詢的條件也跟着複雜起來,這樣簡單的經過一個filter()來進行查詢的條件將致使咱們的查詢愈來愈長。
Q()對象就是爲了將這些條件組合起來。
當咱們在查詢的條件中須要組合條件時(例如兩個條件「且」或者「或」)時。咱們可使用Q()查詢對象。例以下面的代碼
fromdjango.db.modelsimports Q q=Q(question_startswith="What")
這樣就生成了一個Q()對象,咱們可使用符號&或者|將多個Q()對象組合起來傳遞給filter(),exclude(),get()等函數。當多個Q()對象組合起來時,Django會自動生成一個新的Q()。例以下面代碼就將兩個條件組合成了一個
Q(question__startswith='Who') | Q(question__startswith='What')
使用上述代碼可使用SQL語句這麼理解:
WHEREquestionLIKE 'Who%' ORquestionLIKE 'What%'
咱們能夠在Q()對象的前面使用字符「~」來表明意義「非」,例以下面代碼:
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
對應SQL語句能夠理解爲:
WHEREquestionlike "Who%" ORyear(pub_date) !=2005
這樣咱們可使用 「&」或者「|」還有括號來對條件進行分組從而組合成更加複雜的查詢邏輯。
也能夠傳遞多個Q()對象給查詢函數,例以下面代碼:
News.objects,get( Q(question__startswith='Who'), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) )
多個Q()對象之間的關係Django會自動理解成「且(and)」關係。如上面代碼使用SQL語句理解將會是:
SELECT * fromnewsWHEREquestionLIKE 'Who%' AND (pub_date = '2005-05-02' ORpub_date = '2005-05-06')
Q()對象能夠結合關鍵字參數一塊兒傳遞給查詢函數,不過須要注意的是要將Q()對象放在關鍵字參數的前面,看下面代碼
#正確的作法
News.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), question__startswith='Who')
#錯誤的作法,代碼將關鍵字參數放在了Q()對象的前面。
News.objects.get( question__startswith='Who', Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))