2010-09-09 15 views
5

C'è una best practice Django ORM per questo SQL:Django equivalente di SQL SOSTITUIRE

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

Assunzione: Campo_1 o Campo_2 avrebbe una chiave univoca su di loro (o nel mio caso su entrambi), altrimenti questo sarebbe valutare sempre su un INSERT.

Edit:

Il mio migliore risposta personale in questo momento è questo, ma è 2-3 query in cui 1 dovrebbe essere possibile:

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') 

risposta

11

Tu dici che vuoi REPLACE, che credo si suppone elimina qualsiasi riga esistente prima di inserirla, ma il tuo esempio indica che vuoi qualcosa di più come UPSERT.

AFAIK, django non supporta REPLACE (o sqlite's INSERT OR REPLACE o UPSERT). Ma il vostro codice potrebbe essere consolidato:

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

Questo ovviamente presuppone che sia field_1, field_2, o entrambi sono unici (come hai detto).

E 'ancora due interrogazioni (una SELECT per get_or_create e un INSERT o UPDATE per save), ma fino a quando una soluzione UPSERT -come arriva (e potrebbe non per un lungo, lungo tempo), può essere il migliore tu puoi fare.

+4

lol 'get_or_create()' restituisce una tupla '(oggetto, creato)'. Ho fatto lo stesso errore dozzine di volte prima. Questa funzione dovrebbe essere rinominata in "get_a_tuple_or_create()' – est

+0

Good catch, @est. Fisso. – eternicode

4

Penso che quanto segue sia più efficiente.

(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', 
     ], 
    ) 

Questo aggiornerà solo il campo extra se la riga non è stata creata e deve essere aggiornata.

+1

questa è la risposta migliore ... Django aveva l'argomento "default" almeno da 1.3 (i documenti più vecchi che posso ancora trovare online). A proposito, non hai bisogno delle parentesi intorno a '(obj, created)' :) – Anentropic

+1

@Anentropic yeah so che ho un codice OCD piuttosto brutto e per qualche motivo mi è piaciuto molto, ma l'anno scorso ho adottato la maggior parte del Standard di formattazione PEP8, in un modo PEP8 sta abilitando/alimentando il mio codice OCD ancora di più adesso! – byoungb

+0

Lo so, è successo anche a me :) – Anentropic

9

Dal Django 1.7 è possibile utilizzare il metodo update_or_create:

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