2010-09-09 16 views
5

¿Hay un ORM de Django mejores prácticas para este SQL:Django equivalente de SQL REPLACE

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

Supuesto: field_1 o field_2 tendría una clave única en ellos (o en mi caso en ambos), de lo contrario esto sería siempre evaluar a un INSERTAR.

Editar:

Mi mejor respuesta personal en este momento es este, pero es 2-3, donde 1 consultas debería ser posible:

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

Respuesta

11

Usted dice que quiere REPLACE, que creo que se supone que debe eliminar cualquier fila existente antes de insertar, pero su ejemplo indica que desea algo más como UPSERT.

AFAIK, django no admite REPLACE (o sqlite's INSERT OR REPLACE, o UPSERT). Pero su código podría consolidarse:

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

supuesto, esto supone que, o bien field_1, field_2, o ambos son únicos (como se ha dicho).

Es todavía dos consultas (una SELECT para get_or_create, y un INSERT o UPDATE para save), pero hasta una solución UPSERT -como viene (y puede que no por mucho, mucho tiempo), puede ser la mejor tu puedes hacer.

+4

lol 'get_or_create()' 'devuelve una tupla (objeto, creada)'. Cometí el mismo error docenas de veces antes. Esta función realmente debe cambiarse a 'get_a_tuple_or_create()' – est

+0

Buena captura, @est. Fijo. – eternicode

4

Creo que lo siguiente es más eficiente.

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

Esto solo actualizará el campo_extra si la fila no se creó y debe actualizarse.

+1

esta es la mejor respuesta ... Django tenía el arg 'defaults' desde al menos 1.3 (los documentos más antiguos aún puedo encontrar en línea). Por cierto, no necesitas los corchetes alrededor de '(obj, creado)' :) – Anentropic

+1

@Anentropic sí, sé que tengo un código OCD bastante malo y por alguna razón me gustó más, pero en el último año adopté la mayoría de Estándares de formato PEP8, de alguna manera PEP8 está habilitando/alimentando mi código OCD aún más ahora! – byoungb

+0

Lo sé, me pasó lo mismo :) – Anentropic

9

Desde Django 1.7 se puede utilizar update_or_create método:

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