Python类声明问题:类间字段相互引用触发NameError
Python类循环引用及Django模型双向关联解决方案
一、基础Python类循环引用问题
Python代码自上而下顺序执行,定义className1时className2尚未被定义,直接在类属性中实例化className2()会触发NameError。Python没有C++式的前置声明语法,但可以通过两种方式解决:
- 延迟初始化:不在类定义阶段赋值,而是在实例化时(
__init__方法中)创建关联对象:
class className1: def __init__(self): self.fieldClassName2 = className2() class className2: def __init__(self): self.fieldClassName1 = className1()
实例化对象时两个类已完成定义,不会出现未定义错误。
- 字符串引用(框架场景):对于Django等ORM框架,支持用字符串形式指定关联模型名,无需提前定义类。
二、Django模型双向关联的具体修复
你的代码中Speciality和AdmissionList形成双向引用,只需修改Speciality中的abit字段,将模型类名改为字符串形式即可:
class Speciality(models.Model): title = models.CharField(max_length=70) subject1 = models.ManyToManyField(Subject, verbose_name='Перший предмет', related_name='+') subject2 = models.ManyToManyField(Subject, verbose_name='Другий предмет', related_name='+') subject3 = models.ManyToManyField(Subject, verbose_name='Третій предмет', related_name='+') coefficient1 = models.FloatField() coefficient2 = models.FloatField() coefficient3 = models.FloatField() coefficient4 = models.FloatField() amount = models.IntegerField() budget_amount = models.IntegerField() department = models.ForeignKey(Department, verbose_name='Факультет', on_delete=models.CASCADE) code = models.IntegerField(default=0) # 将模型类改为字符串形式 abit = models.ManyToManyField('AdmissionList', verbose_name='Заявки', on_delete=models.CASCADE) def __str__(self): return str(self.code) # 其他模型保持不变 class AdmissionList(models.Model): user = models.ForeignKey(User, verbose_name='Абітурієнт', on_delete=models.CASCADE) speciality = models.ForeignKey(Speciality, verbose_name='Спеціальність', on_delete=models.CASCADE) subject = models.ForeignKey(Subject, on_delete=models.CASCADE, null=True) firstRate = models.IntegerField(default=0) secondRate = models.IntegerField(default=0) thirdRate = models.IntegerField(default=0) avgRate = models.FloatField(default=0) summaryRate = models.FloatField(default=0) is_approved = models.BooleanField(default=False) def __str__(self): return self.user.full_name
如果两个模型属于不同Django应用,需使用'app_label.ModelName'的完整形式(例如'myapp.AdmissionList'),Django会在所有模型加载完成后解析该字符串,找到对应模型类,从而解决循环引用问题。
内容的提问来源于stack exchange,提问作者Илья Власюк
相关产品推荐
相关产品推荐

