使用Django-PolymorphicModel删除实例时触发ValueError错误求助
你的问题出在**父类Question中定义的bonus_question这个OneToOneField**上。这个字段指向BonusQuestion,但所有Question的子类(包括SimpleQuestion、CompoundQuestion)都继承了它。当你删除compound_q时,Django的级联删除机制会遍历它的sub_questions集合(包含SimpleQuestion和BonusQuestion实例),尝试处理每个对象的反向关联。
对于SimpleQuestion实例来说,它的bonus_question关联的是BonusQuestion,但Django在级联收集时,会错误地用SimpleQuestion实例去匹配BonusQuestion的反向关联(related_name='question'),导致类型校验失败——因为这个反向关联要求的是BonusQuestion实例,而不是SimpleQuestion。
方案1:调整字段位置(最推荐)
既然只有SimpleQuestion需要关联BonusQuestion,直接把bonus_question字段移到SimpleQuestion子类中,这样其他子类不会继承这个无关的关联,从根源上避免冲突:
from django.polymorphic import PolymorphicModel class Question(PolymorphicModel): description = models.TextField(default='') compound_question = models.ForeignKey('CompoundQuestion', on_delete=models.CASCADE, blank=True, null=True, related_name='sub_questions') class SimpleQuestion(Question): # 仅在需要的子类中定义该关联 bonus_question = models.OneToOneField('BonusQuestion', on_delete=models.CASCADE, blank=True, null=True, related_name='question') class CompoundQuestion(Question): pass class BonusQuestion(Question): pass
方案2:自定义on_delete行为(保留父类字段时使用)
如果必须把bonus_question留在父类,可以自定义一个on_delete函数,过滤出符合类型的对象再进行级联处理:
from django.db.models.deletion import Collector def custom_cascade(collector, field, sub_objs, using): # 只处理属于BonusQuestion类型的对象,避免类型不匹配 valid_objs = [obj for obj in sub_objs if isinstance(obj, field.remote_field.model)] if valid_objs: collector.collect( valid_objs, source=field.remote_field.model, source_attr=field.name, nullable=field.null ) # 修改父类字段的on_delete参数 class Question(PolymorphicModel): description = models.TextField(default='') compound_question = models.ForeignKey('CompoundQuestion', on_delete=models.CASCADE, blank=True, null=True, related_name='sub_questions') bonus_question = models.OneToOneField('BonusQuestion', on_delete=custom_cascade, blank=True, null=True, related_name='question')
方案3:升级django-polymorphic
这个问题可能是旧版本django-polymorphic的bug,尝试升级到最新稳定版,看看官方是否已经修复了多态模型下级联删除OneToOneField的兼容性问题:
pip install --upgrade django-polymorphic
方案1是最合理的,因为它让模型设计更贴合业务逻辑——只有SimpleQuestion需要和BonusQuestion关联,其他子类不需要这个字段,这样既避免了级联冲突,也让模型结构更清晰。
内容的提问来源于stack exchange,提问作者CimimUxMaio

