get_or_create函數


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)
 
        
它表示從非’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 字段是唯一的它仍然不能創建。


本文出自:https://zhuanlan.zhihu.com/p/34856119



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM