【问题标题】:How can I save objects in bulk with django 1.6如何使用 django 1.6 批量保存对象
【发布时间】:2014-09-19 19:26:17
【问题描述】:

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

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

这段代码可以工作,但是太慢了:

for o in l: o.save()

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

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

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

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

【问题讨论】:

    标签: python django-1.6


    【解决方案1】:

    您可以尝试在修改对象时在对象中设置has_changed 标志,然后仅保存has_changed 为True 的对象。

    这是在假设并非所有对象总是被修改的情况下。如果所有对象总是变化,这不是解决方案。

    【讨论】:

    • 我不会在我检索到的所有对象上调用save。一旦在内存中进行一些计算,我就会遍历所有对象。由该计算修改的那些对象被附加到一个新列表中。最后我要保存的列表只包含已修改的对象。
    • 啊,好吧,我会一直在脑海里思考。
    【解决方案2】:

    Django 不能这样做,因为(通常)你的数据库不能这样做。没有一条 SQL 语句可以用不同的值更新不同的行。 (像使用 CASE...WHEN 这样的特殊例外在这里可能没有帮助。)

    如果许多或大部分对象是新的,您可以使用bulk_create 跟踪并创建这些对象;否则,迭代并执行save() 可能是您最好的选择。

    您可能会考虑使用线程并行化该过程,尤其是在与外部服务通信存在显着延迟的情况下。

    【讨论】:

    • 它可能不必是单个 SQL 语句。背靠背发送多个 SQL 语句并延迟处理回复,可能比完全按顺序处理它们要快得多。
    • 任何原因 django 不能有一个基于 CASE WHEN 的通用 bulk_save 方法,如下所述:stackoverflow.com/a/20255203/3476849
    【解决方案3】:

    我找到了这个解决方法:

    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。

    【讨论】:

    • 我觉得我不应该接受我自己的答案,因为它太窄了,即使它可能是适合我的特殊情况的解决方法,但它不能回答问题的一般版本我说了算。为了实现这一点,它至少必须自动应用于所有适用领域。另外,我的解决方法有点破解。而且我宁愿依赖内置功能而不是构建自己的as_sql 方法。
    • 上述更简洁的实现将使用django.db.models.expressions 而不是我非常hacky的方法。
    猜你喜欢
    • 2011-05-12
    • 1970-01-01
    • 2023-03-27
    • 2015-09-01
    • 1970-01-01
    • 2016-11-18
    • 2023-04-03
    • 1970-01-01
    相关资源
    最近更新 更多