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