在Django中调用父类Event时如何使用子类及孙类的__str__方法?
解决Django模型继承中__str__递归错误的方案
问题原因分析
你原本通过InheritanceManager查询数据库获取子类实例并调用其__str__,但遇到孙类时会触发无限递归:
- 当
Event.__str__查询数据库拿到孙类实例后,若孙类未重写__str__,会调用父类(如FestivalEdition)的__str__ - 若父类的
__str__间接触发Event.__str__,就会形成循环调用,最终抛出RecursionError
另外你的FestivalEdition.__str__存在两处错误:
self.festival_name未定义,应改为self.father_festival.name(关联Festival的name字段)self.year未定义,需在FestivalEdition中添加对应字段
修复方案
无需重复查询数据库,直接利用实例的真实类调用对应__str__,彻底避免递归:
1. 修正后的完整模型代码
from django.db import models from datetime import date from model_utils.managers import InheritanceManager # 需先安装django-model-utils class Event(models.Model): beginning = models.DateTimeField(null=False, blank=True, default=date.today) end = models.DateTimeField(null=False, blank=True, default=date.today) objects2 = InheritanceManager() def __str__(self) -> str: # 获取实例的真实类(而非当前声明的Event类) actual_class = self.__class__ # 若真实类不是Event本身,直接调用对应类的__str__方法 if actual_class != Event: return actual_class.__str__(self) # 纯Event实例的默认显示 return f"Event object ({self.pk})" class Festival(models.Model): name = models.CharField(max_length=100, blank=True) def __str__(self) -> str: return self.name or "Unnamed Festival" class FestivalEdition(Event): type = "festival_edition" father_festival = models.ForeignKey(Festival, on_delete=models.CASCADE, related_name="edition") year = models.IntegerField() # 添加缺失的year字段 def __str__(self) -> str: # 修正字段引用 return f"{self.father_festival.name} {self.year}" # 示例孙类(即使不重写__str__也不会触发递归) class SpecialFestivalEdition(FestivalEdition): special_note = models.CharField(max_length=200, blank=True)
2. 关键修复点
- 通过
self.__class__直接获取实例的真实类型,避免重复查询数据库,提升性能 - 调用
actual_class.__str__(self)而非self.__str__(),绕开方法解析顺序中可能触发的父类__str__调用,彻底阻断递归路径 - 纯
Event实例返回默认标识,保证基础场景的显示正常
3. 依赖安装
确保已安装django-model-utils库:
pip install django-model-utils
修改后,无论子类还是孙类实例,在以Event类型被调用时,都会正确显示对应子类的__str__内容,且不会触发递归错误。
内容的提问来源于stack exchange,提问作者Dhrions
相关产品推荐
相关产品推荐

