我正在写一个Django应用程序,我需要一个函数来更新数据库中的一个字段。有没有理由使用其中一个方法而不是另一个?
def save_db_field(name,field,value):
obj = MyModel.objects.get(name=name)
obj.field = value
obj.save()
def update_db_field(name,field,value):
MyModel.objects.get(name=name).update(field=value)
看起来第二种更好,因为它在一个DB调用中完成,而不是两个。有什么原因可以解释为什么先获取,然后更新更好吗?
9条答案
按热度按时间c9qzyr3d1#
有几个关键的区别。
update
用于查询集,因此可以一次更新多个对象。正如@FallenAngel所指出的,定制
save()
方法的触发方式存在差异,但记住signals
和ModelManagers
也很重要。我构建了一个小的测试应用程序来展示一些有价值的差异。我使用的是Python 2.7.5,Django==1.7.7和SQLite,注意最终的SQL在不同版本的Django和不同的数据库引擎上可能会有所不同。好了,下面是示例代码。
models.py
:views.py
:这导致了以下SQL查询:
我们只有一个针对
update()
的查询和两个针对save()
的查询。接下来,我们来讨论覆盖
save()
方法。显然,save()
方法只调用一次。值得一提的是,.objects.create()
也调用save()
方法。但是
update()
在模型上不调用save()
,如果update()
没有调用save()
方法,那么信号也不会触发,输出:如你所见,
save()
触发Manager
的get_queryset()
两次,而update()
只触发一次。解决方案。如果您需要“静默”更新您的值,而不调用
save()
-请使用update
。last_seen
用户字段。当您需要正确更新模型时,请使用save()
。gk7wooem2#
两者看起来相似,但有一些关键点:
save()
将触发任何被覆盖的Model.save()
方法,但update()
不会触发此操作并在数据库级别进行直接更新。因此,如果您有一些带有被覆盖的保存方法的模型,则必须避免使用update或找到其他方法来执行您正在对被覆盖的save()
方法执行的任何操作。obj.save()
可能会有一些副作用,如果你不小心的话。你用get(...)
来检索对象,所有的模型字段值都会传递给你的obj。当你调用obj.save()
时,django会保存当前对象的状态以记录。所以如果get()
和save()
之间发生了一些变化,那么那些改变将会丢失.使用save(update_fields=[.....])
来避免这样的问题.1.在Django1.5版本之前,Django在
INSERT
/UPDATE
之前执行SELECT
,因此需要2次查询执行。在这里,有一个很好的指南或
save()
和update()
方法以及如何执行它们。ffscu2ro3#
保存()方法可以插入新记录和更新已有记录,一般用于保存数据库中单个记录(mysql中为行)的示例。
update()不用于插入记录,可用于更新数据库中的多个记录(mysql中的行)。
qqrboqgw4#
直接使用update更高效,还可以防止完整性问题。
来自官方文档docs.djangoproject.com/en/3.0/ref/models/querysets/#django.db.models.query.QuerySet.update
如果你只是更新一条记录,而不需要对模型对象做任何事情,最有效的方法是调用update(),而不是将模型对象加载到内存中。
...执行以下操作:
使用update()还可以防止出现争用情况,即在加载对象和调用保存()之间的短时间内,数据库中可能会发生一些变化。
jyztefdp5#
更新只适用于更新查询集。如果你想同时更新多个字段,比如说从一个对象示例的dict中,你可以执行如下操作:
请记住,字典必须包含正确的Map,其中键需要是字段名,值需要是要插入的值。
3b6akqbq6#
Update将为您提供更好的性能与多个对象的查询集,因为它将使每个查询集一个数据库调用。
然而保存是有用的,因为它很容易覆盖模型中的save方法并添加额外的逻辑,例如,在我自己的应用程序中,当其他字段改变时,我更新一个日期。
xzabzqsa7#
使用_state.adding区分更新和创建https://docs.djangoproject.com/en/3.2/ref/models/instances/
kuarbcqp8#
其中一个差异可能会导致很多麻烦,即
save
更新,但update
不更新类型为DateTimeField(auto_now=True)
或ModificationDateTimeField
的列。这些字段(应该)在对象保存到数据库时自动设置其日期。o0lyfsai9#
一月一日:
QuerySet
或Manager
对象**一起使用。select_for_update()
可以运行SELECT FOR UPDATE
查询**。一个月五个月一个月
QuerySet
或Manager
对象一起使用,但不能与模型对象**一起使用。select_for_update()
的无法运行SELECT FOR UPDATE
查询**。例如,我有**
Person
型号**,如下所示:然后,您可以将**
save()
与Person
模型对象一起使用,如下所示:x一个一个一个一个x一个一个二个x
但是,您不能将
save()
与QuerySet
对象**一起使用,如下所示:然后,出现以下错误:
属性错误:“QuerySet”对象没有属性“保存”
而且,您不能将**
save()
与Manager
对象**一起使用,如下所示:然后,出现以下错误:
属性错误:“Manager”对象没有属性“保存”
然后,您可以将**
update()
与QuerySet
对象**一起使用,如下所示:而且,您可以将**
update()
与Manager
对象**一起使用,如下所示:但是,不能将**
update()
与Person
模型对象**一起使用,如下所示:然后,出现以下错误:
属性错误:“Person”对象没有属性“update”
例如,
select_for_update()
用于防止在Django中更新数据时出现争用情况(更新丢失或写入偏斜)。并且,我有**
test
视图**,其中包含**save()
和select_for_update().filter(pk=1).first()
**,如下所示:然后,当我运行**
test
view时,SELECT FOR UPDATE
和UPDATE
查询将如下所示运行。* 我使用了PostgreSQL**,下面的这些日志是PostgreSQL的查询日志,您可以检查在PostgreSQL上,如何记录带有事务查询的SQL查询,例如“开始”和“COMMIT”:现在,我删除**
first()
以使用update()
**,如下所示:然后,当我运行**
test
视图时,SELECT FOR UPDATE
查询没有运行,而只运行了UPDATE
查询**,如下所示:而且,我有**
test
视图**,其中包含**save()
和select_for_update().get(pk=1)
**,如下所示:然后,当我运行**
test
view时,SELECT FOR UPDATE
和UPDATE
查询**将按如下所示运行:现在,我删除**
get()
以使用update()
**,如下所示:然后,当我运行**
test
view时,SELECT FOR UPDATE
query没有运行,而只运行了UPDATE
query**,如下所示:因此,带有**
select_for_update()
的save()
可以运行SELECT FOR UPDATE
查询**,而带有**select_for_update()
的update()
**则不能。