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

前端 未结 4 1216
执笔经年
执笔经年 2020-12-04 06:06

What it the difference between running two commands:

foo = FooModel()

and

bar = BarModel.objects.create()

相关标签:
4条回答
  • 2020-12-04 06:20

    The two syntaxes are not equivalent and it can lead to unexpected errors. Here is a simple example showing the differences. If you have a model:

    from django.db import models
    
    class Test(models.Model):
    
        added = models.DateTimeField(auto_now_add=True)
    

    And you create a first object:

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

    Then you try to create an object with the same primary key:

    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")
    
    0 讨论(0)
  • 2020-12-04 06:30

    The difference between Model() vs Model.objects.create() are summarized as below.


    1. .save() perform internally as either INSERT or UPDATE object to db, while .objects.create() perform only INSERT object to db.

      Model.save() perform ....

      UPDATE → If the object’s primary key attribute is set to a value that evaluates to True

      INSERT → If the object’s primary key attribute is not set or if the UPDATE didn’t update anything (e.g. if primary key is set to a value that doesn’t exist in the database).


    1. If primary key attribute is set to a value then Model.save() perform UPDATE but Model.objects.create raise IntegrityError.

      eg.

      models.py

      class Subject(models.Model):
         subject_id = models.PositiveIntegerField(primary_key=True, db_column='subject_id')
         name = models.CharField(max_length=255)
         max_marks = models.PositiveIntegerField()
      

      1) Insert/Update to db with Model.save()

      physics = Subject(subject_id=1, name='Physics', max_marks=100)
      physics.save()
      math = Subject(subject_id=1, name='Math', max_marks=50)  # Case of update
      math.save()
      

      Output:

      Subject.objects.all().values()
      <QuerySet [{'subject_id': 1, 'name': 'Math', 'max_marks': 50}]>
      

      2) Insert to db with Model.objects.create()

      Subject.objects.create(subject_id=1, name='Chemistry', max_marks=100)
      IntegrityError: UNIQUE constraint failed: m****t.subject_id
      

      Explanation: Above math.save() is case of update since subject_id is primary key and subject_id=1 exists django internally perform UPDATE, name Physics to Math and max_marks from 100 to 50 for this, but objects.create() raise IntegrityError


    1. Model.objects.create() not equivalent to Model.save() however same can be achieved with force_insert=True parameter on save method i.e Model.save(force_insert=True).

    1. Model.save() return None where Model.objects.create() return model instance i.e. package_name.models.Model

    Conclusion: Model.objects.create() internally do model initialization and perform save with force_insert=True.

    source-code block of Model.objects.create()

    def create(self, **kwargs):
        """
        Create a new object with the given kwargs, saving it to the database
        and returning the created object.
        """
        obj = self.model(**kwargs)
        self._for_write = True
        obj.save(force_insert=True, using=self.db)
        return obj
    

    The following links can be followed for more details:

    1. https://docs.djangoproject.com/en/stable/ref/models/querysets/#create

    2. https://github.com/django/django/blob/2d8dcba03aae200aaa103ec1e69f0a0038ec2f85/django/db/models/query.py#L440

    0 讨论(0)
  • 2020-12-04 06:36

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

    To create and save an object in a single step, use the create() method.

    0 讨论(0)
  • 2020-12-04 06:39

    UPDATE 15.3.2017:

    I have opened a Django-issue on this and it seems to be preliminary accepted here: https://code.djangoproject.com/ticket/27825

    My experience is that when using the Constructor (ORM) class by references with Django 1.10.5 there might be some inconsistencies in the data (i.e. the attributes of the created object may get the type of the input data instead of the casted type of the ORM object property) example:

    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
    
    0 讨论(0)
提交回复
热议问题