如何使用django 1.6批量保存对象

时间:2014-09-19 19:26:17

标签: python django-1.6

我正在寻找一种更有效地更新多个对象的方法,而不是在每个对象上调用.save()

我有代码,它使用.filter()来加载对象。然后它与外部服务通信,以决定每个对象需要做什么。最后,我有一个包含更新值的对象列表,我需要保存。

此代码有效,但速度太慢:

for o in l: o.save()

搜索我到目前为止的建议.bulk_create().update()

bulk_create非常适合新对象。但用model.objects.bulk_create(l)替换上面的循环会产生IntegrityError: UNIQUE constraint failed:,可能是因为它试图创建新对象而不是更新现有对象。

使用.update()似乎也不适用于我的用例,因为它将使用相同的值更新集合中的所有对象。在我的情况下,我为每个对象计算了一个不同的值,我需要保存它。

是否有比在每个对象上调用.save()更快的解决方案?

3 个答案:

答案 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。