【问题标题】:Django Model() vs Model.objects.create()Django Model() 与 Model.objects.create()
【发布时间】:2014-12-27 14:53:21
【问题描述】:

运行两个命令有什么区别:

foo = FooModel()

bar = BarModel.objects.create()

第二个是否立即在数据库中创建BarModel,而对于FooModel,必须显式调用save() 方法才能将其添加到数据库中?

【问题讨论】:

标签: python django database django-models


【解决方案1】:

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

要在一个步骤中创建和保存对象,请使用create() 方法。

【讨论】:

  • 在我看来,django 文档在这一点上有点矛盾。我有同样的问题并阅读了“请注意,实例化模型绝不会触及您的数据库;为此,您需要保存()。” docs.djangoproject.com/en/1.10/ref/models/instances/…
  • 我认为这并不矛盾。通常在python中,您通过在对象名称后放置方括号而不是通过创建方法来实例化对象
  • @danidee 我同意这并不矛盾,但肯定会产生误导。主要是因为在 Nils 的链接中,example1 是“实例化”,但 example2 是“实例化+保存”。另外,当我想知道如何保存模型时,为什么要参考“查询”文档? django doc 真的有很多痛点。
  • @Nakamura 因为 INSERT 是一个查询?
  • @madzohan 我认为文档更改为完全相反:“要创建一个对象,请使用模型类的关键字参数对其进行实例化,然后调用 save() 将其保存到数据库中。”
【解决方案2】:

Model()Model.objects.create() 的区别如下:


  1. 插入与更新

    Model.save() 对数据库中的对象执行 INSERT 或 UPDATE,而 Model.objects.create() 仅执行 INSERT。

    Model.save()

    • UPDATE如果对象的主键属性设置为一个评估为True的值

    • INSERT 如果对象的主键属性未设置或 UPDATE 未更新任何内容(例如,如果主键设置为数据库中不存在的值)。


  1. 现有的主键

    如果主键属性设置为一个值并且这样的主键已经存在,那么Model.save()执行UPDATE,但Model.objects.create()引发IntegrityError

    考虑以下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. 使用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()
      

      结果:

      Subject.objects.all().values()
      <QuerySet [{'subject_id': 1, 'name': 'Math', 'max_marks': 50}]>
      
    2. 使用Model.objects.create()插入数据库

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

    解释:在示例中,math.save() 执行更新(将 namePhysics 更改为 Math,以及 max_marks从 100 到 50),因为 subject_id 是主键并且 subject_id=1 已经存在于数据库中。但是Subject.objects.create() 引发IntegrityError,因为,主键subject_id 的值1 已经存在。


  1. 强制插入

    Model.save() 可以通过使用force_insert=True 参数:Model.save(force_insert=True) 来表现为Model.objects.create()


  1. 返回值

    Model.save() return None where Model.objects.create() return model instance 即package_name.models.Model


结论:Model.objects.create() 进行模型初始化并执行save()force_insert=True

摘自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

更多详情请点击以下链接:

  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

【讨论】:

    【解决方案3】:

    这两种语法不等效,可能会导致意外错误。 这是一个显示差异的简单示例。 如果您有模型:

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

    然后你创建了第一个对象:

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

    然后你尝试创建一个具有相同主键的对象:

    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() 即使缺少必填字段 (null=False) 也会创建一个对象?我正在向我的项目添加测试,create 得到了意想不到的结果
    • 不,它不应该......虽然有些字段类型在 Django 中表现得有点奇怪。例如,CharField 即使设置为null=False,如果未提供也不会引发错误:这是因为 Django 将字符串默认设置为空字符串"",所以从技术上讲它不是null
    • 是的,我只遇到字符字段和字段字段(基本上也是字符字段)的问题。现在使用obj = MyModel(),然后使用obj.full_clean()
    【解决方案4】:

    2017 年 3 月 15 日更新:

    我已经为此打开了一个 Django 问题,它似乎在这里被初步接受: https://code.djangoproject.com/ticket/27825

    我的经验是,当使用Constructor(ORM) 类通过Django 1.10.5 引用时,数据中可能会出现一些不一致(即创建对象的属性可能会获取输入数据的类型)而不是 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
    

    【讨论】:

    • Josh Smeaton 给出了excellent answer 关于开发人员自己对类型转换的责任。请更新您的答案。
    【解决方案5】:

    Model.objects.create() 创建一个模型实例并保存它。 Model() 只创建一个内存模型实例。在调用实例的save() 方法保存它之前,它不会保存到数据库中。这也是验证发生的时候。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-08-18
      • 2017-07-12
      • 2017-01-13
      • 2014-03-23
      • 2012-12-16
      • 2021-11-13
      • 2012-11-01
      相关资源
      最近更新 更多