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

267

Quelle est la différence entre l'exécution de deux commandes:

foo = FooModel()

et

bar = BarModel.objects.create()

Le second crée-t-il immédiatement un BarModeldans la base de données, alors que pour FooModel, la save()méthode doit être appelée explicitement pour l'ajouter à la base de données?

0leg
la source
47
Oui, c'est ça la différence.
Daniel Roseman

Réponses:

247

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

Pour créer et enregistrer un objet en une seule étape, utilisez la create()méthode.

madzohan
la source
3
Les django docs sont un peu contradictoires sur ce point à mon avis. J'ai eu la même question et j'ai lu "Notez que l'instanciation d'un modèle ne touche en rien votre base de données; pour cela, vous devez enregistrer ()." docs.djangoproject.com/en/1.10/ref/models/instances/…
Nils
6
Je ne vois pas cela comme contradictoire. Généralement en python, vous instanciez des objets en mettant des crochets après le nom des objets et non par une méthode create
danidee
3
@danidee Je suis d'accord, ce n'est pas contradictoire, mais c'est certainement trompeur. Principalement parce que dans le lien de Nils, l'exemple1 est "instanciant" mais l'exemple2 est "instanciant + sauvant". Aussi, pourquoi devrais-je me référer au document "requêtes" quand je veux savoir comment enregistrer un modèle? Il y a vraiment beaucoup de douleurs dans django doc.
Nakamura
3
@Nakamura car INSERT est une requête?
Juanjo Conti
16

Les deux syntaxes ne sont pas équivalentes et peuvent entraîner des erreurs inattendues. Voici un exemple simple montrant les différences. Si vous avez un modèle:

from django.db import models

class Test(models.Model):

    added = models.DateTimeField(auto_now_add=True)

Et vous créez un premier objet:

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

Ensuite, vous essayez de créer un objet avec la même clé primaire:

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
la source
.create()crée donc un objet même si un champ obligatoire ( null=False) est manquant? create
J'ajoute des
Non, cela ne devrait pas ... Bien que certains types de champs agissent un peu bizarrement dans Django. Par exemple, CharFieldmême s'il est défini sur null=Falsene soulèvera pas d'erreur s'il n'est pas fourni: cela est dû au fait que Django définit les chaînes par défaut sur une chaîne vide, ""donc ce n'est pas techniquementnull
Thomas Leonard
ouais, je rencontre des problèmes uniquement avec les champs char et field field (qui est essentiellement le champ char aussi). Utilisation obj = MyModel(), alors obj.full_clean()pour l'instant.
Vaibhav Vishal
10

MISE À JOUR 15.3.2017:

J'ai ouvert un problème Django à ce sujet et il semble être accepté au préalable ici: https://code.djangoproject.com/ticket/27825

D'après mon expérience, lors de l'utilisation de la classe Constructor( ORM) par des références avec Django, 1.10.5il peut y avoir des incohérences dans les données (c'est-à-dire que les attributs de l'objet créé peuvent obtenir le type des données d'entrée au lieu du type casté de la propriété d'objet ORM) exemple :

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
la source
Josh Smeaton a donné une excellente réponse concernant la responsabilité du développeur quant aux types de distribution. Veuillez mettre à jour votre réponse.
Artur Barseghyan