Be careful with related_name
and related_query_name
¶
If you are using related_name
or related_query_name
on a ForeignKey
or ManyToManyField
, you must always specify a unique reverse name and query name for the field. This would normally cause a problem in abstract base classes, since the fields on this class are included into each of the child classes, with exactly the same values for the attributes (including related_name
and related_query_name
) each time.
To work around this problem, when you are using related_name
or related_query_name
in an abstract base class (only), part of the value should contain '%(app_label)s'
and '%(class)s'
.
'%(class)s'
is replaced by the lowercased name of the child class that the field is used in.'%(app_label)s'
is replaced by the lowercased name of the app the child class is contained within. Each installed application name must be unique and the model class names within each app must also be unique, therefore the resulting name will end up being different.
For example, given an app common/models.py
:
from django.db import models
class Base(models.Model):
m2m = models.ManyToManyField(
OtherModel,
related_name="%(app_label)s_%(class)s_related",
related_query_name="%(app_label)s_%(class)ss",
)
class Meta:
abstract = True
class ChildA(Base):
pass
class ChildB(Base):
pass
Along with another app rare/models.py
:
from common.models import Base
class ChildB(Base):
pass
The reverse name of the common.ChildA.m2m
field will be common_childa_related
and the reverse query name will be common_childas
. The reverse name of the common.ChildB.m2m
field will be common_childb_related
and the reverse query name will be common_childbs
. Finally, the reverse name of the rare.ChildB.m2m
field will be rare_childb_related
and the reverse query name will be rare_childbs
. It’s up to you how you use the '%(class)s'
and '%(app_label)s'
portion to construct your related name or related query name but if you forget to use it, Django will raise errors when you perform system checks (or run migrate
).
If you don’t specify a related_name
attribute for a field in an abstract base class, the default reverse name will be the name of the child class followed by '_set'
, just as it normally would be if you’d declared the field directly on the child class. For example, in the above code, if the related_name
attribute was omitted, the reverse name for the m2m
field would be childa_set
in the ChildA
case and childb_set
for the ChildB
field.
总结: 相对来讲,自设定的优势更好!