如下的方法不會返回QuerySets,可是做用很是強大,尤爲是粗體顯示的方法,須要背下來。python
方法名 | 解釋 |
---|---|
get() | 獲取單個對象 |
create() | 建立對象,無需save() |
get_or_create() | 查詢對象,若是沒有找到就新建對象 |
update_or_create() | 更新對象,若是沒有找到就建立對象 |
bulk_create() |
批量建立對象 |
count() | 統計對象的個數 |
in_bulk() |
根據主鍵值的列表,批量返回對象 |
iterator() |
獲取包含對象的迭代器 |
latest() | 獲取最近的對象 |
earliest() | 獲取最先的對象 |
first() | 獲取第一個對象 |
last() | 獲取最後一個對象 |
aggregate() | 聚合操做 |
exists() | 判斷queryset中是否有對象 |
update() | 批量更新對象 |
delete() | 批量刪除對象 |
as_manager() | 獲取管理器 |
get(**kwargs)web
返回按照查詢參數匹配到的單個對象,參數的格式應該符合Field lookups的要求。數據庫
若是匹配到的對象個數不僅一個的話,觸發MultipleObjectsReturned異常django
若是根據給出的參數匹配不到對象的話,觸發DoesNotExist異常。例如:後端
Entry.objects.get(id='foo') # raises Entry.DoesNotExist
DoesNotExist異常從django.core.exceptions.ObjectDoesNotExist
繼承,能夠定位多個DoesNotExist異常。 例如:緩存
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.")
若是但願查詢器只返回一行,則可使用get()而不使用任何參數來返回該行的對象:安全
entry = Entry.objects.filter(...).exclude(...).get()
create(**kwargs)函數
在一步操做中同時建立而且保存對象的便捷方法.post
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()調用。 若是查找到一個對象,返回一個包含匹配到的對象以及False 組成的元組。 若是查找到的對象超過一個以上,將引起MultipleObjectsReturned。若是查找不到對象,get_or_create()
將會實例化並保存一個新的對象,返回一個由新的對象以及True組成的元組。新的對象將會按照如下的邏輯建立:
params = {k: v for k, v in kwargs.items() if '__' not in k} params.update({k: v() if callable(v) else v for k, v in defaults.items()}) obj = self.model(**params) obj.save()
它表示從非'defaults' 且不包含雙下劃線的關鍵字參數開始。而後將defaults的內容添加進來,覆蓋必要的鍵,並使用結果做爲關鍵字參數傳遞給模型類。
若是有一個名爲defaults__exact
的字段,而且想在get_or_create()
時用它做爲精確查詢,只須要使用defaults,像這樣:
Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})
當你使用手動指定的主鍵時,get_or_create()
方法與create()
方法有類似的錯誤行爲 。 若是須要建立一個對象而該對象的主鍵早已存在於數據庫中,IntegrityError異常將會被觸發。
這個方法假設進行的是原子操做,而且正確地配置了數據庫和正確的底層數據庫行爲。若是數據庫級別沒有對get_or_create
中用到的kwargs強制要求惟一性(unique和unique_together),方法容易致使競態條件,可能會有相同參數的多行同時插入。(簡單理解,kwargs必須指定的是主鍵或者unique屬性的字段才安全。)
最後建議只在Django視圖的POST請求中使用get_or_create(),由於這是一個具備修改性質的動做,不該該使用在GET請求中,那樣不安全。
能夠經過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」,可是它不能,由於它與這個book不關聯,但由於title 字段是惟一的它仍然不能建立。
在Django1.11在defaults中增長了對可調用值的支持。
update_or_create(defaults=None, **kwargs)
相似前面的get_or_create()
。
經過給出的kwargs來更新對象的便捷方法, 若是沒找到對象,則建立一個新的對象。defaults是一個由 (field, value)對組成的字典,用於更新對象。defaults中的值能夠是可調用對象(也就是說函數等)。
該方法返回一個由(object, created)組成的元組,元組中的object是一個建立的或者是被更新的對象, created是一個標示是否建立了新的對象的布爾值。
update_or_create
方法嘗試經過給出的kwargs 去從數據庫中獲取匹配的對象。 若是找到匹配的對象,它將會依據defaults 字典給出的值更新字段。
像下面的代碼:
defaults = {'first_name': 'Bob'} try: obj = Person.objects.get(first_name='John', last_name='Lennon') for key, value in defaults.items(): setattr(obj, key, value) obj.save() except Person.DoesNotExist: new_values = {'first_name': 'John', 'last_name': 'Lennon'} new_values.update(defaults) obj = Person(**new_values) obj.save()
若是模型的字段數量較大的話,這種模式就變的很是不易用了。 上面的示例能夠用update_or_create()
重寫:
obj, created = Person.objects.update_or_create( first_name='John', last_name='Lennon', defaults={'first_name': 'Bob'}, )
kwargs中的名稱如何解析的詳細描述能夠參見get_or_create()
。
和get_or_create()
同樣,這個方法也容易致使競態條件,若是數據庫層級沒有前置惟一性會讓多行同時插入。
在Django1.11在defaults中增長了對可調用值的支持。
bulk_create(objs, batch_size=None)
以高效的方式(一般只有1個查詢,不管有多少對象)將提供的對象列表插入到數據庫中:
>>> Entry.objects.bulk_create([ ... Entry(headline='This is a test'), ... Entry(headline='This is only a test'), ... ])
注意事項:
pre_save
和post_save
信號。batch_size
參數控制在單個查詢中建立的對象數。
count()
返回在數據庫中對應的QuerySet對象的個數。count()永遠不會引起異常。
例如:
# 返回總個數. Entry.objects.count() # 返回包含有'Lennon'的對象的總數 Entry.objects.filter(headline__contains='Lennon').count()
in_bulk(id_list=None)
獲取主鍵值的列表,並返回將每一個主鍵值映射到具備給定ID的對象的實例的字典。 若是未提供列表,則會返回查詢集中的全部對象。
例如:
>>> 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([]) {} >>> Blog.objects.in_bulk() {1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}
若是向in_bulk()
傳遞一個空列表,會獲得一個空的字典。
在舊版本中,id_list
是必需的參數,如今是一個可選參數。
iterator()
提交數據庫操做,獲取QuerySet,並返回一個迭代器。
QuerySet一般會在內部緩存其結果,以便在重複計算時不會致使額外的查詢。而iterator()將直接讀取結果,不在QuerySet級別執行任何緩存。對於返回大量只須要訪問一次的對象的QuerySet,這能夠帶來更好的性能,顯著減小內存使用。
請注意,在已經提交了的iterator()上使用QuerySet會強制它再次提交數據庫操做,進行重複查詢。此外,使用iterator()會致使先前的prefetch_related()
調用被忽略,由於這兩個一塊兒優化沒有意義。
latest(field_name=None)
使用日期字段field_name,按日期返回最新對象。
下例根據Entry的'pub_date'字段返回最新發布的entry:
Entry.objects.latest('pub_date')
若是模型的Meta指定了get_latest_by
,則能夠將latest()參數留給earliest()或者field_name
。 默認狀況下,Django將使用get_latest_by
中指定的字段。
earliest()和latest()可能會返回空日期的實例,可能須要過濾掉空值:
Entry.objects.filter(pub_date__isnull=False).latest('pub_date')
earliest(field_name=None)
類同latest()。
first()
返回結果集的第一個對象, 當沒有找到時返回None。若是QuerySet沒有設置排序,則將會自動按主鍵進行排序。例如:
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進行計算。每一個參數指定返回的字典中將要包含的值。
使用關鍵字參數指定的聚合將使用關鍵字參數的名稱做爲Annotation 的名稱。 匿名參數的名稱將基於聚合函數的名稱和模型字段生成。 複雜的聚合不可使用匿名參數,必須指定一個關鍵字參數做爲別名。
例如,想知道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。
查找具備惟一性字段(例如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")
update(**kwargs)
對指定的字段執行批量更新操做,並返回匹配的行數(若是某些行已具備新值,則可能不等於已更新的行數)。
例如,要對2010年發佈的全部博客條目啓用評論,能夠執行如下操做:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
能夠同時更新多個字段 (沒有多少字段的限制)。 例如同時更新comments_on和headline字段:
>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')
update()方法無需save操做。惟一限制是它只能更新模型主表中的列,而不是關聯的模型,例如不能這樣作:
>>> Entry.objects.update(blog__name='foo') # Won't work!
仍然能夠根據相關字段進行過濾:
>>> Entry.objects.filter(blog__id=1).update(comments_on=True)
update()方法返回受影響的行數:
>>> Entry.objects.filter(id=64).update(comments_on=True) 1 >>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True) 0 >>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False) 132
若是你只是更新一下對象,不須要爲對象作別的事情,最有效的方法是調用update(),而不是將模型對象加載到內存中。 例如,不要這樣作:
e = Entry.objects.get(id=10) e.comments_on = False e.save()
建議以下操做:
Entry.objects.filter(id=10).update(comments_on=False)
用update()還能夠防止在加載對象和調用save()之間的短期內數據庫中某些內容可能發生更改的競爭條件。
若是想更新一個具備自定義save()方法的模型的記錄,請循環遍歷它們並調用save(),以下所示:
for e in Entry.objects.filter(pub_date__year=2010): e.comments_on = False e.save()
delete()
批量刪除QuerySet中的全部對象,並返回刪除的對象個數和每一個對象類型的刪除次數的字典。
delete()動做是當即執行的。
不能在QuerySet上調用delete()。
例如,要刪除特定博客中的全部條目:
>>> b = Blog.objects.get(pk=1) # Delete all the entries belonging to this Blog. >>> Entry.objects.filter(blog=b).delete() (4, {'weblog.Entry': 2, 'weblog.Entry_authors': 2})
默認狀況下,Django的ForeignKey使用SQL約束ON DELETE CASCADE,任何具備指向要刪除的對象的外鍵的對象將與它們一塊兒被刪除。 像這樣:
>>> blogs = Blog.objects.all() # This will delete all Blogs and all of their Entry objects. >>> blogs.delete() (5, {'weblog.Blog': 1, 'weblog.Entry': 2, 'weblog.Entry_authors': 2})
這種級聯的行爲能夠經過的ForeignKey的on_delete參數自定義。(何時要改變這種行爲呢?好比日誌數據,就不能和它關聯的主體一併被刪除!)
delete()會爲全部已刪除的對象(包括級聯刪除)發出pre_delete
和post_delete
信號。
classmethod as_manager()
一個類方法,返回Manager的實例與QuerySet的方法的副本。