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

267

Qual a diferença entre executar dois comandos:

foo = FooModel()

e

bar = BarModel.objects.create()

O segundo cria imediatamente um BarModelno banco de dados, enquanto que para FooModelo save()método deve ser chamado explicitamente para adicioná-lo ao banco de dados?

0leg
fonte
47
Sim, essa é a diferença.
Daniel Roseman 31/10

Respostas:

247

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

Para criar e salvar um objeto em uma única etapa, use o create()método

madzohan
fonte
3
Os documentos do django são um pouco contraditórios sobre esse ponto na minha opinião. Eu tive a mesma pergunta e li "Observe que a instanciação de um modelo não afeta seu banco de dados; para isso, você precisa salvar ()." docs.djangoproject.com/en/1.10/ref/models/instances/…
Nils
6
Não vejo isso como contraditório. Geralmente, em Python, você instanciar objetos, colocando entre parênteses após os objetos não citar por um método de criar
danidee
3
@danidee Concordo que não é contraditório, mas certamente é enganoso. Principalmente porque no link de Nils, o exemplo1 é "instanciando", mas o exemplo2 é "instanciando + salvando". Além disso, por que devo consultar o documento "consultas" quando quero saber como salvar um modelo? Há realmente muitas dores no django doc.
Nakamura
3
@Nakamura porque INSERT é uma consulta?
Juanjo Conti 28/11
16

As duas sintaxes não são equivalentes e podem levar a erros inesperados. Aqui está um exemplo simples mostrando as diferenças. Se você tem um modelo:

from django.db import models

class Test(models.Model):

    added = models.DateTimeField(auto_now_add=True)

E você cria um primeiro objeto:

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

Então você tenta criar um objeto com a mesma chave primária:

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
fonte
por isso .create()cria um objeto, mesmo se um campo obrigatório ( null=False) está faltando? Estou adicionando testes para meu projeto e createestá a ter resultados inesperados
Vaibhav Vishal
Não, não deveria ... Embora alguns tipos de campo sejam um pouco estranhos no Django. Por exemplo, CharFieldmesmo que definido para null=Falsenão gerar um erro se não for fornecido: isso é porque Django definir cordas por padrão para uma cadeia vazia ""para que ele não é tecnicamentenull
Thomas Leonard
Sim, estou tendo problemas apenas com campos de caracteres e campos de campos (que também são basicamente campos de caracteres). Usando obj = MyModel(), então obj.full_clean()por enquanto.
precisa saber é o seguinte
10

ATUALIZAÇÃO 15.3.2017:

Eu abri uma questão do Django sobre isso e parece ser preliminar aceito aqui: https://code.djangoproject.com/ticket/27825

Minha experiência é que, ao usar a classe Constructor( ORM) por referências com o Django 1.10.5, pode haver algumas inconsistências nos dados (ou seja, os atributos do objeto criado podem obter o tipo dos dados de entrada em vez do tipo convertido da propriedade do 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
fonte
Josh Smeaton deu uma excelente resposta sobre a responsabilidade do desenvolvedor de transmitir tipos. Por favor, atualize sua resposta.
Artur Barseghyan 9/09/19