Cree el modelo Django o actualice si existe

115

Quiero crear un objeto modelo, como Persona, si la identificación de la persona no existe, o obtendré ese objeto de persona.

El código para crear una nueva persona de la siguiente manera:

class Person(models.Model):
    identifier = models.CharField(max_length = 10)
    name = models.CharField(max_length = 20)
    objects = PersonManager()

class PersonManager(models.Manager):
    def create_person(self, identifier):
        person = self.create(identifier = identifier)
        return person

Pero no sé dónde verificar y obtener el objeto de persona existente.

user1687717
fuente

Respuestas:

169

Si está buscando un caso de uso "actualizar si existe, crear", consulte la excelente respuesta de @Zags


Django ya tiene un get_or_create, https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create

Para ti podría ser:

id = 'some identifier'
person, created = Person.objects.get_or_create(identifier=id)

if created:
   # means you have created a new person
else:
   # person just refers to the existing one
bakkal
fuente
Estoy usando django 1.9 y me está dando: AttributeError: el objeto 'QuerySet' no tiene atributo 'update_or_create'
Ofek Gila
1
@OfekGila Eso es extraño, tanto el código fuente como la documentación confirman que QuerySettieneupdate_or_create
bakkal
2
En mi caso, en lugar de identificador, tengo un grupo de campos que forman unique_together. ¿Cómo es el uso para este caso?
Rakmo
191

No está claro si su pregunta solicita el método get_or_create (disponible al menos en Django 1.3) o el método update_or_create (nuevo en Django 1.7). Depende de cómo desee actualizar el objeto de usuario.

El uso de muestra es el siguiente:

# In both cases, the call will get a person object with matching
# identifier or create one if none exists; if a person is created,
# it will be created with name equal to the value in `name`.

# In this case, if the Person already exists, its existing name is preserved
person, created = Person.objects.get_or_create(
        identifier=identifier, defaults={"name": name}
)

# In this case, if the Person already exists, its name is updated
person, created = Person.objects.update_or_create(
        identifier=identifier, defaults={"name": name}
)
Zags
fuente
12
+1 update_or_createporque para ese caso de uso es mejor que get_or_createsimplemente llamar save()al objeto nuevamente.
bakkal
En mi caso, en lugar de identificador, tengo un grupo de campos que forman unique_together. ¿Cómo es el uso para este caso?
Rakmo
1
El identificador @OmkarDeshpande es solo un ejemplo; puede pasar cualquier consulta válida de Django, comoPerson.objects.get_or_create(a=a, b=b, c=c, defaults={"name": name})
Zags
¿Qué sucede si quiero agregar más campos a la Persona creada que los predeterminados?
Lo Bellin
@LoBellin, el defaultsargumento de estas funciones es donde especifica qué campos desea agregar al modelo. No tiene nada que ver con los valores predeterminados especificados en los campos de su modelo
Zags
10

Django tiene soporte para esto, verifique get_or_create

person, created = Person.objects.get_or_create(name='abc')
if created:
    # A new person object created
else:
    # person object already exists
Aamir Adnan
fuente
4

Para solo una pequeña cantidad de objetos, update_or_create funciona bien, pero si lo está haciendo sobre una colección grande, no escalará bien. update_or_create siempre ejecuta primero un SELECT y luego un UPDATE.

for the_bar in bars:
    updated_rows = SomeModel.objects.filter(bar=the_bar).update(foo=100)
        if not updated_rows:
            # if not exists, create new
            SomeModel.objects.create(bar=the_bar, foo=100)

Esto, en el mejor de los casos, solo ejecutará la primera consulta de actualización, y solo si coincide con cero filas ejecutará otra consulta INSERT. Lo que aumentará enormemente su rendimiento si espera que la mayoría de las filas existan realmente.

Sin embargo, todo se reduce a su caso de uso. Si está esperando mayormente inserciones, quizás el comando bulk_create () podría ser una opción.

Andreas Bergström
fuente
3

Pensé que agregaría una respuesta, ya que el título de su pregunta parece preguntar cómo crear o actualizar, en lugar de obtener o crear como se describe en el cuerpo de la pregunta.

Si desea crear o actualizar un objeto, el método .save () ya tiene este comportamiento por defecto, de los documentos :

Django abstrae la necesidad de utilizar sentencias INSERT o UPDATE SQL. Específicamente, cuando llamas a save (), Django sigue este algoritmo:

Si el atributo de clave principal del objeto se establece en un valor que se evalúa como Verdadero (es decir, un valor que no sea Ninguno o la cadena vacía), Django ejecuta una ACTUALIZACIÓN. Si el atributo de clave principal del objeto no está configurado o si la ACTUALIZACIÓN no actualizó nada, Django ejecuta un INSERT.

Vale la pena señalar que cuando dicen 'si la ACTUALIZACIÓN no actualizó nada', esencialmente se refieren al caso en el que la identificación que le dio al objeto no existe ya en la base de datos.

Tom Manterfield
fuente
1

Si una de las entradas cuando crea es una clave principal, esto será suficiente:

Person.objects.get_or_create(id=1)

Se actualizará automáticamente si existe, ya que no se permiten dos datos con la misma clave primaria.

Aminah Nuraini
fuente