我正在寻找一种更有效地更新多个对象的方法,而不是在每个对象上调用.save()
。
我有代码,它使用.filter()
来加载对象。然后它与外部服务通信,以决定每个对象需要做什么。最后,我有一个包含更新值的对象列表,我需要保存。
此代码有效,但速度太慢:
for o in l: o.save()
搜索我到目前为止的建议.bulk_create()
和.update()
bulk_create
非常适合新对象。但用model.objects.bulk_create(l)
替换上面的循环会产生IntegrityError: UNIQUE constraint failed:
,可能是因为它试图创建新对象而不是更新现有对象。
使用.update()
似乎也不适用于我的用例,因为它将使用相同的值更新集合中的所有对象。在我的情况下,我为每个对象计算了一个不同的值,我需要保存它。
是否有比在每个对象上调用.save()
更快的解决方案?
答案 0 :(得分:0)
您可以尝试在修改对象时设置has_changed
标记,然后仅保存has_changed
为True的对象。
这是假设并非总是修改所有对象。如果所有对象总是在变化,那么这不是解决方案。
答案 1 :(得分:0)
Django不能这样做,因为(一般来说)你的数据库不能这样做。没有单个SQL语句可以使用不同的值更新不同的行。 (使用CASE...WHEN
等特殊例外情况不太可能对此有所帮助。)
如果许多或大多数对象是新的,您可以跟踪哪些对象并使用bulk_create
创建对象;否则,迭代和做save()
可能是你最好的选择。
您可以考虑使用线程并行化该过程,尤其是在与外部服务进行通信的重要延迟时。
答案 2 :(得分:0)
我发现了这个解决方法:
class CASE(object):
def __init__(self, field_name, objects):
self.field_name = field_name
self.objects = objects
def __unicode__(self): return self
def as_sql(self, qn, connection):
sql = [ 'CASE id' ]
params = []
for o in self.objects:
sql.append('WHEN %s THEN %s')
params.append(o.pk)
params.append(getattr(o, self.field_name))
sql.append('ELSE')
sql.append(qn(self.field_name))
sql.append('END')
return (' '.join(sql), params)
model.objects.update(value=CASE('value', l))
它并不漂亮,但据我所知,只要我只是更新一个文本字段,它确实会生成正确有效的SQL。