Django Model () vs Model.objects.create ()

267

Cuál es la diferencia entre ejecutar dos comandos:

foo = FooModel()

y

bar = BarModel.objects.create()

¿El segundo crea inmediatamente un BarModelen la base de datos, mientras que para FooModelel save()método debe llamarse explícitamente para agregarlo a la base de datos?

0 pierna
fuente
47
Sí, esa es la diferencia.
Daniel Roseman

Respuestas:

247

https://docs.djangoproject.com/en/stable/topics/db/queries/#creating-objects

Para crear y guardar un objeto en un solo paso, use el create()método

madzohan
fuente
3
Los documentos de django son un poco contradictorios en este punto en mi opinión. He tenido la misma pregunta y leí "Tenga en cuenta que crear instancias de un modelo de ninguna manera toca su base de datos; para eso, debe guardar ()". docs.djangoproject.com/en/1.10/ref/models/instances/…
Nils
66
No veo eso como contradictorio. En general, en pitón, crear instancias de objetos, poniendo entre paréntesis después de que los objetos no nombran por un método de crear
danidee
3
@danidee Estoy de acuerdo en que no es contradictorio, pero ciertamente es engañoso. Principalmente porque en el enlace de Nils, ejemplo1 es "instanciar" pero ejemplo2 es "instanciar + guardar". Además, ¿por qué debería referirme al documento de "consultas" cuando quiero saber cómo guardar un modelo? Realmente hay muchos dolores en django doc.
Nakamura
3
@Nakamura porque INSERT es una consulta?
Juanjo Conti
16

Las dos sintaxis no son equivalentes y pueden provocar errores inesperados. Aquí hay un ejemplo simple que muestra las diferencias. Si tienes un modelo:

from django.db import models

class Test(models.Model):

    added = models.DateTimeField(auto_now_add=True)

Y creas un primer objeto:

foo = Test.objects.create(pk=1)

Luego intenta crear un objeto con la misma clave primaria:

foo_duplicate = Test.objects.create(pk=1)
# returns the error:
# django.db.utils.IntegrityError: (1062, "Duplicate entry '1' for key 'PRIMARY'")

foo_duplicate = Test(pk=1).save()
# returns the error:
# django.db.utils.IntegrityError: (1048, "Column 'added' cannot be null")
Thomas Leonard
fuente
entonces .create()crea un objeto incluso si falta un campo requerido ( null=False)? Estoy agregando pruebas a mi proyecto y estoy createteniendo resultados inesperados
Vaibhav Vishal
No, no debería ... Aunque algunos tipos de campo actúan un poco raro en Django. Por ejemplo, CharFieldincluso si se establece en null=Falseno generará un error si no se proporciona: esto se debe a que Django establece las cadenas de forma predeterminada en una cadena vacía, ""por lo que no es técnicamentenull
Thomas Leonard
Sí, estoy teniendo problemas solo con los campos de caracteres y el campo de campos (que también es básicamente campo de caracteres) Usando obj = MyModel(), entonces obj.full_clean()por ahora.
Vaibhav Vishal
10

ACTUALIZACIÓN 15.3.2017:

He abierto un problema de Django sobre esto y parece ser aceptado preliminarmente aquí: https://code.djangoproject.com/ticket/27825

Mi experiencia es que cuando se usa la clase Constructor( ORM) por referencias con Django 1.10.5puede haber algunas inconsistencias en los datos (es decir, los atributos del objeto creado pueden obtener el tipo de los datos de entrada en lugar del tipo fundido de la propiedad del objeto ORM) :

models

class Payment(models.Model):
     amount_cash = models.DecimalField()

some_test.py - object.create

Class SomeTestCase:
    def generate_orm_obj(self, _constructor, base_data=None, modifiers=None):
        objs = []
        if not base_data:
            base_data = {'amount_case': 123.00}
        for modifier in modifiers:
            actual_data = deepcopy(base_data)
            actual_data.update(modifier)
            # Hacky fix,
            _obj = _constructor.objects.create(**actual_data)
            print(type(_obj.amount_cash)) # Decimal
            assert created
           objs.append(_obj)
        return objs

some_test.py - Constructor()

Class SomeTestCase:
    def generate_orm_obj(self, _constructor, base_data=None, modifiers=None):
        objs = []
        if not base_data:
            base_data = {'amount_case': 123.00}
        for modifier in modifiers:
            actual_data = deepcopy(base_data)
            actual_data.update(modifier)
            # Hacky fix,
            _obj = _constructor(**actual_data)
            print(type(_obj.amount_cash)) # Float
            assert created
           objs.append(_obj)
        return objs
Oleg Belousov
fuente
Josh Smeaton dio una excelente respuesta con respecto a la responsabilidad del desarrollador de emitir tipos. Por favor, actualice su respuesta.
Artur Barseghyan