Django Model() 和 Model.objects.create() 区别

433

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

foo = FooModel()

bar = BarModel.objects.create()

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


95
没问题,那就是区别所在。 - Daniel Roseman
这是一直都正确的吗?我在 Django 文档中看到过这样的地方,在使用 *.objects.create() 创建实例后,他们会在实例上调用 save()。就像这里 https://docs.djangoproject.com/en/3.1/topics/db/models/#extra-fields-on-many-to-many-relationships - Aleksandr Mikheev
@Aleksandr Mikheev:我在那40个“create”文本出现之后没有看到.save()。如果您想要说什么,请发布一个链接,该链接指向简短的代码示例,而不是10页的文本。为什么您要毫无根据地让其他人感到不确定呢? - mirek
5个回答

363

3
在我看来,Django文档在这一点上有些矛盾。我也有同样的问题,并阅读了“请注意,实例化模型并不会对您的数据库产生任何影响;要实现这一点,您需要保存()。”的内容。https://docs.djangoproject.com/en/1.10/ref/models/instances/#creating-objects - Nils
12
我认为这并不矛盾。通常在Python中,您可以通过在对象名称后面加上括号而不是使用创建方法来实例化对象。 - danidee
4
@danidee,我同意这并不是矛盾的,但肯定是误导性的。主要是因为在Nils的链接中,例子1是“实例化”,但例子2是“实例化+保存”。 此外,当我想知道如何保存模型时,为什么要参考“查询”文档?Django文档确实有很多缺陷。 - Nakamura
7
@Nakamura 因为 INSERT 是一个查询语句吗? - Juanjo Conti
1
@MartinThoma 实际上没有改变,使用我的答案中的引用和 Ctrl+F ... 顺便说一句,不要点赞它,我是认真的,伙计们 - 只需阅读那些令人惊叹的文档 :) 和平! - madzohan
显示剩余2条评论

64

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


  1. INSERT vs UPDATE

    Model.save() 可以将对象插入或更新到数据库中,而 Model.objects.create() 只能插入新的对象。

    Model.save() 的行为如下:

    • 更新 若对象的主键属性设置为一个等价于 True 的值。

    • 插入 若对象的主键属性未设置或者如果更新操作没有更新任何内容(例如,主键设置为数据库中不存在的值)。


  1. 已经存在的主键

    如果将主键属性设置为一个已经存在的值,那么 Model.save() 将执行更新操作,但是 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()将数据插入到数据库中

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

解释: 在这个例子中,math.save() 执行了一个 UPDATE(将 namePhysics 更改为 Math,将 max_marks 从 100 更改为 50),因为 subject_id 是主键且 subject_id=1 已经存在于数据库中。但是,Subject.objects.create() 抛出了 IntegrityError,因为再次使用值为 1 的主键 subject_id 已经存在。


  1. 强制插入

    可以通过使用 force_insert=True 参数,使 Model.save() 表现得像 Model.objects.create()Model.save(force_insert=True)


  1. 返回值

    Model.save() 返回 None,而 Model.objects.create() 返回模型实例,即 package_name.models.Model


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

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


4
这个回答比被采纳的回答好得多且更有帮助。 - jcgoble3

24

这两种语法不等同,会导致意外错误。以下是一个简单的示例,展示了它们之间的差异。

如果你有一个模型:

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

1
那么.create()即使缺少必需字段(null=False),也会创建一个对象吗?我正在为我的项目添加测试,但create的结果出乎意料。 - Vaibhav Vishal
不应该这样...尽管在Django中,一些字段类型的行为有点奇怪。 例如,即使将CharField设为null=False,如果没有提供值,它也不会引发错误:这是因为Django默认将字符串设置为空字符串"",因此在技术上它不是null - Thomas Leonard
1
是的,我只在char字段和field字段(基本上也是char字段)方面遇到了问题。目前使用obj = MyModel(),然后obj.full_clean() - Vaibhav Vishal

14

更新于2017年3月15日:

我在Django问题跟踪中提出了这个问题,并且似乎初步已被接受: https://code.djangoproject.com/ticket/27825

我的经验是,在使用Django 1.10.5Constructor (ORM)类通过引用时,数据可能存在一些不一致性。(例如:创建的对象的属性可能会获取输入数据的类型而不是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在关于开发者自己负责类型转换的问题上给出了优秀的回答。请更新您的回答。 - Artur Barseghyan

6

Model.objects.create() 创建一个模型实例并将其保存。 Model() 只是在内存中创建了一个模型实例,只有在调用该实例的save()方法保存时才会将其保存到数据库中。此时还会进行验证。


两者有什么好处? - Vaidøtas I.
@VaidøtasI- 在第二个中,您可以使用 Model.objects.using('database').create()。如果您使用多租户,这将非常方便。 - kta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接