Django抽象模型中能否声明两个指向同表的ForeignKey?
在Django ORM抽象模型中声明两个指向同一张表的ForeignKey的解决方案
你想在抽象模型TrackableDateModel中同时添加create_user和update_user两个指向User表的ForeignKey,但添加update_user后执行makemigrations时出现反向访问器冲突报错:
ERRORS:
DjModule.A.create_user: (fields.E304) Reverse accessor 'User.create_user' for 'DjModule.A.create_user' clashes with reverse accessor for DjModule.B.create_user'.
HINT: Add or change a related_name argument to the definition for 'DjModule.A.Export4Payment.create_user' or 'DjModule.B.create_user'.
原代码如下:
class TrackableDateModel(models.Model): """Abstract model to Track the creation/updated date for a model.""" create_date = models.DateTimeField(auto_now_add=True, help_text="Creation time", verbose_name="Created", null=True, blank=True) create_user = models.ForeignKey(User, related_name="create_user", on_delete=models.CASCADE, help_text="Who created", verbose_name="Author", null=True, blank=True) update_date = models.DateTimeField(auto_now=True, help_text="Time of change", verbose_name="Changed", null=True, blank=True) class Meta: abstract = True class A(TrackableDateModel): .... class B(TrackableDateModel): .....
尝试添加的字段:
update_user = models.ForeignKey(User, related_name="update_user", on_delete=models.CASCADE, help_text="Who modified", verbose_name="Author of change", null=True, blank=True)
错误原因
所有继承该抽象模型的子类(比如A、B)会共享相同的related_name值,导致User模型上生成的反向访问器名称重复,引发冲突。
解决办法
使用Django提供的%(class)s占位符,让每个子类的related_name自动带上自身类名,避免重复。修改后的抽象模型代码如下:
from django.contrib.auth.models import User from django.db import models class TrackableDateModel(models.Model): """Abstract model to Track the creation/updated date for a model.""" create_date = models.DateTimeField(auto_now_add=True, help_text="Creation time", verbose_name="Created", null=True, blank=True) create_user = models.ForeignKey( User, related_name="created_%(class)s", on_delete=models.CASCADE, help_text="Who created", verbose_name="Author", null=True, blank=True ) update_date = models.DateTimeField(auto_now=True, help_text="Time of change", verbose_name="Changed", null=True, blank=True) update_user = models.ForeignKey( User, related_name="updated_%(class)s", on_delete=models.CASCADE, help_text="Who modified", verbose_name="Author of change", null=True, blank=True ) class Meta: abstract = True class A(TrackableDateModel): # 子类自定义字段 pass class B(TrackableDateModel): # 子类自定义字段 pass
效果说明
- 对于
A类,create_user对应的反向访问器变为User.created_a.all(),update_user对应的反向访问器变为User.updated_a.all() - 对于
B类,反向访问器则是User.created_b.all()和User.updated_b.all() - 这样就不会出现反向访问器名称冲突的问题,执行
makemigrations和migrate都能正常完成
内容的提问来源于stack exchange,提问作者Victor
相关产品推荐
相关产品推荐

