Django - 高效地批量创建继承模型

Posted

技术标签:

【中文标题】Django - 高效地批量创建继承模型【英文标题】:Django - Efficiently bulk create inherited models 【发布时间】:2015-02-26 23:39:21 【问题描述】:

Python 2.7.9 Django 1.7 MySQL 5.6

我想填充属于多个类的一大堆对象实例,将它们堆叠成一个类似create() 的查询,打开数据库连接,执行查询,然后关闭。我的主要动机是性能,但代码紧凑性也是一个优点。

bulk_create() 的功能似乎正是我想要的,但我至少违反了here 列出的警告之一,即

它不适用于多对多关系。

它不适用于多表继承场景中的子模型。

the source code 中也描述了这些限制:

# So this case is fun. When you bulk insert you don't get the primary
# keys back (if it's an autoincrement), so you can't insert into the
# child tables which references this. There are two workarounds, 1)
# this could be implemented if you didn't have an autoincrement pk,
# and 2) you could do it by doing O(n) normal inserts into the parent
# tables to get the primary keys back, and then doing a single bulk
# insert into the childmost table. Some databases might allow doing
# this by using RETURNING clause for the insert query. We're punting
# on these for now because they are relatively rare cases.

但是当我尝试它时返回的错误是通用的

ValueError: 无法批量创建继承模型

我的模型显然不包含任何多对多字段或外键。我并不完全清楚他们指的是什么多表继承场景,所以我不确定这是否是我的问题。我希望我的结构看起来像这样,但后来我得到了一般错误,所以没有骰子:

child class with OneToOneField---\
                                  \   
child class with OneToOneField----->---concrete parent class
                                  /
child class with OneToOneField---/

就源代码中建议的解决方法而言,#1 对我来说不是一个选项,而#2 看起来并不吸引人,因为我认为这将需要牺牲我所追求的性能增益。

是否有其他解决方法可以模拟bulk_create(),同时处理这样的继承而不放弃性能提升?我需要回到原始 SQL 吗?我不介意为每个子对象类型创建一个单独的集合并执行一个单独的INSERT/create()

【问题讨论】:

【参考方案1】:

我确定的解决方法是将我收集的所有create()s 包装在with transaction.atomic(): 中。通过在所有 Python 返回之前不打开任何数据库连接或执行任何查询,这大大减少了运行时间。

缺点可能是,如果遇到任何错误,所有更改都会回滚并且数据库不会受到影响。这可以通过将create()s 分成多个批次并围绕每个批次打开和关闭一个事务来解决。 (在我的情况下,这不是所需的行为,因为我想要所有数据或一个都不想要。)

【讨论】:

以上是关于Django - 高效地批量创建继承模型的主要内容,如果未能解决你的问题,请参考以下文章

如何在不在 python 中迭代它们的情况下明显地批量更新 django 模型的所有对象?

Django ORM批量操作和foreign key

Django ORM 中的批量操作

使用 Django Rest Framework 的 ListSerializer 批量创建

python Django批量创建/更新

Django 批处理/批量更新或创建?