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?


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.


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

.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

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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.