执行makemigrations时Django表单触发AttributeError异常
问题排查:执行makemigrations时触发AttributeError错误
错误回溯信息
File "/Users/luketimothy/Library/Mobile Documents/com~apple~CloudDocs/LifePlanner/LifePlanner/LifePlanner/urls.py", line 20, in <module> from . import views File "/Users/luketimothy/Library/Mobile Documents/com~apple~CloudDocs/LifePlanner/LifePlanner/LifePlanner/views.py", line 7, in <module> from .forms import AppUserForm, IncomeSourceForm, AccountForm, SpouseForm, DependentForm File "/Users/luketimothy/Library/Mobile Documents/com~apple~CloudDocs/LifePlanner/LifePlanner/LifePlanner/forms.py", line 32, in <module> class AccountForm(forms.ModelForm): File "/Users/luketimothy/Library/Mobile Documents/com~apple~CloudDocs/LifePlanner/LifePlanner/ProjectEnv/lib/python3.11/site-packages/django/forms/models.py", line 312, in __new__ fields = fields_for_model( ^^^^^^^^^^^^^^^^^ File "/Users/luketimothy/Library/Mobile Documents/com~apple~CloudDocs/LifePlanner/LifePlanner/ProjectEnv/lib/python3.11/site-packages/django/forms/models.py", line 237, in fields_for_model formfield = f.formfield(**kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/Users/luketimothy/Library/Mobile Documents/com~apple~CloudDocs/LifePlanner/LifePlanner/ProjectEnv/lib/python3.11/site-packages/django/db/models/fields/related.py", line 1165, in formfield "queryset": self.remote_field.model._default_manager.using(using), ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'using'
相关代码片段
forms.py 中的 AccountForm
class AccountForm(forms.ModelForm): class Meta: model = Account fields = ['account_name','owner','account_provider','balance'] labels = {'account_name': 'Name','account_provider': 'Account Provider','balance': 'Balance','owner': 'Owner'}
models.py 相关模型
class Projectable(models.Model): class Meta: abstract = True def project_annual_values(self, years): raise NotImplementedError("Subclasses should implement this method.") def project_monthly_values(self, months): raise NotImplementedError("Subclasses should implement this method.") class AccountProvider(models.Model): name = models.CharField(max_length=64) web_url = models.CharField(max_length=256) login_url = models.CharField(max_length=256) logo_file= models.CharField(max_length=64) def __str__(self): return f"{self.name}" class Account(Projectable): account_name = models.CharField(max_length=100) balance = models.DecimalField(max_digits=15, decimal_places=2) owner = models.ForeignKey(Agent, on_delete=models.CASCADE) account_provider = models.ForeignKey(AccountProvider, on_delete=models.SET_NULL) def get_balance(self): return self.balance def get_account_type(self): raise NotImplementedError("Subclasses should implement this method.")
Agent 抽象模型
class Agent(models.Model): retirement_age = models.IntegerField() date_of_birth = models.DateField() name = models.CharField(max_length=100) class Meta: abstract = True
问题原因
核心问题在于Account模型的owner字段直接关联了抽象模型Agent。Django的外键字段要求关联实际存在的数据表模型,而抽象模型不会生成数据表,也没有对应的模型管理器,导致Django无法解析owner字段的关联目标,最终出现remote_field.model为None的情况,触发AttributeError。
另外,account_provider字段使用了on_delete=models.SET_NULL但未设置null=True,这也是潜在问题,后续迁移时会报错。
解决方法
方案1:将Agent改为非抽象模型
如果Agent需要作为独立的数据表存在,直接移除其Meta类中的abstract = True:
class Agent(models.Model): retirement_age = models.IntegerField() date_of_birth = models.DateField() name = models.CharField(max_length=100) # 移除抽象模型设置 # class Meta: # abstract = True
同时给account_provider字段补充null=True:
account_provider = models.ForeignKey(AccountProvider, on_delete=models.SET_NULL, null=True)
方案2:使用GenericForeignKey关联Agent的子类
如果Agent必须作为抽象模型,供多个子类(如AppUser、Spouse)继承,那么需要用GenericForeignKey来实现关联:
- 先导入必要的模块:
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey
- 修改Account模型的
owner字段:
class Account(Projectable): account_name = models.CharField(max_length=100) balance = models.DecimalField(max_digits=15, decimal_places=2) # 替换原有的外键字段 content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() owner = GenericForeignKey('content_type', 'object_id') # 补充null=True account_provider = models.ForeignKey(AccountProvider, on_delete=models.SET_NULL, null=True) def get_balance(self): return self.balance def get_account_type(self): raise NotImplementedError("Subclasses should implement this method.")
修改完成后,重新执行makemigrations和migrate命令即可。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

