2010-09-09 13 views
5

Gibt es eine Django ORM beste Praxis für diese SQL:Django Äquivalent von SQL REPLACE

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

Annahme: field_1 oder field_2 würde einen eindeutigen Schlüssel auf sie haben (oder in meinem Fall auf beide), sonst würde dies immer zu einem INSERT auswerten.

Edit:

Meine beste jetzt persönliche Antwort ist, aber es ist 2-3 Abfragen, wobei 1 möglich sein sollte:

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

Antwort

11

Sie sagen, Sie REPLACE wollen, was ich glaube, soll löschen Sie alle vorhandenen Zeilen vor dem Einfügen, aber Ihr Beispiel zeigt, dass Sie etwas mehr wie UPSERT möchten.

AFAIK, django unterstützt REPLACE (oder sqlites INSERT OR REPLACE oder UPSERT) nicht. Aber Ihr Code könnte konsolidiert:

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

Dies setzt natürlich voraus, dass entweder field_1, field_2 oder beide eindeutig sind (wie Sie gesagt haben).

Es ist immer noch zwei Abfragen (a SELECT für get_or_create und ein INSERT oder UPDATE für save), aber bis eine UPSERT -ähnlichen Lösung zusammen kommt (und es kann nicht für eine lange, lange Zeit), kann es das Beste sein du kannst tun.

+4

lol 'get_or_create()' gibt ein Tupel '(Objekt, erstellt)'. Ich habe den gleichen Fehler schon Dutzende Male gemacht. Diese Funktion sollte wirklich umbenannt werden in 'get_a_tuple_or_create()' – est

+0

Guter Fang, @est. Fest. – eternicode

4

Ich denke, das Folgende ist effizienter.

Dies aktualisiert nur das extra_field, wenn die Zeile nicht erstellt wurde und aktualisiert werden muss.

+1

das ist die bessere Antwort ... Django hatte die "defaults" arg seit mindestens 1.3 (älteste Dokumente, die ich noch online finden kann). BTW du brauchst nicht die Klammern um '(obj, erstellt)' :) – Anentropic

+1

@Anentropic ja Ich weiß, ich habe ziemlich schlecht Code OCD und aus irgendeinem Grund mochte ich das besser, aber im vergangenen Jahr habe ich die meisten übernommen PEP8 Formatierungsstandards, so wie PEP8 meinen Code OCD jetzt noch mehr aktiviert/füttert! – byoungb

+0

Ich weiß, das gleiche passiert mir :) – Anentropic

9

Da Django 1.7 können Sie update_or_create Methode verwenden:

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