问题
我使用的是django-model-utils InheritanceManager。我有一个超级通知(models.Model)类,我使用它来创建许多通知子类,如PostNotification(Notification)、CommentNotification(Notification)等,当尝试运行CommentNotification.objects.bulk_create(list_of_comment_notification_objects)时,我得到以下回溯:
File "/home/me/.virtualenvs/project/local/lib/python2.7/site-packages/django/db/models/query.py", line 429, in bulk_create
raise ValueError("Can't bulk create a multi-table inherited model")
ValueError: Can't bulk create a multi-table inherited model在检查query.py文件时,我们得到以下导致错误的原因:
for parent in self.model._meta.get_parent_list():
if parent._meta.concrete_model is not self.model._meta.concrete_model:
raise ValueError("Can't bulk create a multi-table inherited model")环境Django Model Utils版本: 3.1.1 Django版本: 1.11.7 Python版本: 2.7.3
示例
PostNotification.objects.bulk_create(
[PostNotification(related_user=user, post=instance) for user in users]
)抛出上面的异常
我尝试过的,虽然最初是成功的:
我认为这只是简单地运行:BaseClass.objects.bulk_create(list_of_SubClass_objects)而不是SubClass.objects.bulk_create(list_of_SubClass_objects)可以工作并返回一个SubClass值列表,但随后运行SubClass.objects.all()将返回一个空结果。bulk_create()只会为列表中的每个项目创建一个通知基类对象。
发布于 2020-07-15 00:25:23
找到了一个老生常谈的解决方案。我希望它适用于你的情况。诀窍是动态创建一个具有某些元(db_table)集的模型(不是继承的模型)。并使用此动态模型批量创建子对象(换句话说,写入Child的DB表)。
class Parent(models.Model):
name = models.CharField(max_length=10)
class Child(Parent):
phone = models.CharField(max_length=12)# just an example. Should be expanded to work properly.
field_type_mapping = {
'OneToOneField': models.IntegerField,
'CharField': models.CharField,
}
def create_model(Model, app_label='children', module='', options=None):
"""
Create specified model
"""
model_name = Model.__name__
class Meta:
managed = False
db_table = Model._meta.db_table
if app_label:
# app_label must be set using the Meta inner class
setattr(Meta, 'app_label', app_label)
# Update Meta with any options that were provided
if options is not None:
for key, value in options.iteritems():
setattr(Meta, key, value)
# Set up a dictionary to simulate declarations within a class
attrs = {'__module__': module, 'Meta': Meta}
# Add in any fields that were provided
fields = dict()
for field in Model._meta.fields:
if field.attname == 'id':
continue
if field.model.__name__ == model_name:
field_class_name = type(field).__name__
print(field.attname)
fields[field.attname] = field_type_mapping[field_class_name]()
# Create the class, which automatically triggers ModelBase processing
attrs.update(fields)
model = type(f'{model_name}Shadow', (models.Model,), attrs)
return model
mod = create_model(Child)
parents = [Parent(name=i) for i in range(15)]
parents = Parent.objects.bulk_create(parents)
children = [mod(phone=parent.name, parent_ptr_id=parent.id) for parent in parents]
mod.objects.bulk_create(children)发布于 2021-07-20 21:58:14
我做了一个bulk_create的自定义实现,它似乎对我的情况有效(只有一个父关系,而不是自动递增的pk):
from django.db import models
class MultiTableChildQueryset(models.QuerySet):
def bulk_create(self, objs, batch_size=None):
assert batch_size is None or batch_size > 0
if not objs:
return objs
self._for_write = True
objs = list(objs)
parent_model = self.model._meta.pk.related_model
parent_objs = []
for obj in objs:
parent_values = {}
for field in [f for f in parent_model._meta.fields if hasattr(obj, f.name)]:
parent_values[field.name] = getattr(obj, field.name)
parent_objs.append(parent_model(**parent_values))
setattr(obj, self.model._meta.pk.attname, obj.id)
parent_model.objects.bulk_create(parent_objs, batch_size=batch_size)
with transaction.atomic(using=self.db, savepoint=False):
self._batched_insert(objs, self.model._meta.local_fields, batch_size)
return objshttps://stackoverflow.com/questions/49826482
复制相似问题