2010-09-09 32 views
5

是否有此SQL Django的ORM最佳實踐:的Django相當於SQL的更換

REPLACE app_model SET field_1 = 'some val', field_2 = 'some val'; 

假設:field_1或field_2會對它們(或在我的兩個情況)的唯一密鑰,否則這會總是評估爲INSERT。

編輯:

我最好的個人的答案,現在是這樣的,但它是2-3查詢,其中1應該是可能的:

from django.core.exceptions import ValidationError 
    try: 
     Model(field_1='some val',field_2='some val').validate_unique() 
     Model(field_1='some val',field_2='some val',extra_field='some val').save() 
    except ValidationError: 
     Model.objects.filter(field_1='some val',field_2='some val').update(extra_field='some val') 

回答

11

你說要REPLACE,我相信應該是刪除插入前的任何現有行,但您的示例表明您需要更像UPSERT的內容。

AFAIK,django不支持REPLACE(或sqlite的INSERT OR REPLACEUPSERT)。但是,你的代碼可以合併:

obj, created = Model.objects.get_or_create(field_1='some val', field_2='some_val') 
obj.extra_field = 'some_val' 
obj.save() 

當然,這是假設,要麼field_1field_2,或者兩者都是獨一無二的(如你說的)。

它仍然是兩個查詢(get_or_create一個SELECT,並saveINSERTUPDATE),但直到UPSERT樣的解決方案出現時(它可能不是一個很長很長的時間),這可能是最好的你可以做。

+4

洛爾'get_or_create()'返回一個元組'(對象,創建)'。我幾十次犯了同樣的錯誤。這個函數真的應該重命名爲'get_a_tuple_or_create()' – est 2012-09-03 04:01:52

+0

好抓,@est。固定。 – eternicode 2012-09-07 13:32:36

4

我認爲以下更有效。

(obj, created) = Model.objects.get_or_create(
    field_1 = 'some val', 
    field_2 = 'some_val', 
    defaults = { 
     'extra_field': 'some_val' 
    }, 
) 
if not created and obj.extra_field != 'some_val': 
    obj.extra_field = 'some_val' 
    obj.save(
     update_fields = [ 
     'extra_field', 
     ], 
    ) 

如果該行未被創建並且需要更新,這將只更新extra_field。

+1

這是更好的答案... Django具有'defaults' arg,因爲它至少有1.3(最老的文檔,我仍然可以在網上找到)。順便說一句,你不需要'(obj,created)'周圍的括號:) – Anentropic 2016-01-27 17:13:19

+1

@Antropic是的我知道我有非常糟糕的代碼強迫症,由於某種原因,我更喜歡,但在過去的一年中,我採用了大部分PEP8格式化標準,PEP8現在可以啓用/提供我的代碼OCD了! – byoungb 2016-01-28 00:01:28

+0

我知道,同樣發生在我身上:) – Anentropic 2016-01-28 11:04:37

9

由於Django的1.7可以使用update_or_create方法:

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon', defaults=updated_values)