一尘不染

如何在Django中执行批量插入?

sql

在mysql中,您可以在一个查询中为n> 0插入多行到一个表中:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9), ..., (n-2, n-1, n);

有没有一种方法可以使用Django queryset方法实现以上目标?这是一个例子:

values = [(1, 2, 3), (4, 5, 6), ...]

for value in values:
    SomeModel.objects.create(first=value[0], second=value[1], third=value[2])

我相信上面为for循环的每次迭代都调用了插入查询。我正在寻找一个查询,这在Django中可能吗?


阅读 163

收藏
2021-03-17

共1个答案

一尘不染

最近,我本人也在寻找这样的东西(受到QuerySet.update()的启发,就像我想的那样)。据我所知,当前的生产框架(截至目前为1.1.1)中不存在大量创建的内容。我们最终为需要批量创建的模型创建了一个自定义管理器,并在该管理器上创建了一个函数,以使用VALUES参数序列构建适当的SQL语句。

诸如此类的东西(如果无法解决,请您道歉…希望我已经从我们的代码中很好地适应了这一点):

from django.db import models, connection

class MyManager(models.Manager):

    def create_in_bulk(self, values):
        base_sql = "INSERT INTO tbl_name (a,b,c) VALUES "
        values_sql = []
        values_data = []

        for value_list in values:
            placeholders = ['%s' for i in range(len(value_list))]
            values_sql.append("(%s)" % ','.join(placeholders))
            values_data.extend(value_list)

        sql = '%s%s' % (base_sql, ', '.join(values_sql))

        curs = connection.cursor()
        curs.execute(sql, values_data)

class MyObject(models.Model):
    # model definition as usual... assume:
    foo = models.CharField(max_length=128)

    # custom manager
    objects = MyManager()

MyObject.objects.create_in_bulk( [('hello',), ('bye',), ('c', )] )

这种方法确实存在特定于特定数据库的风险。在我们的例子中,我们希望函数返回刚刚创建的ID,因此我们在函数中进行了postgres特定的查询,以从代表对象的表的主键序列中生成所需数量的ID。也就是说,与迭代数据和发出单独的QuerySet.create()语句相比,它在测试中的性能确实要好得多。

2021-03-17