Django: Why do some model fields clash with each other?
PythonDjangoDjango ModelsPython Problem Overview
I want to create an object that contains 2 links to Users. For example:
class GameClaim(models.Model):
target = models.ForeignKey(User)
claimer = models.ForeignKey(User)
isAccepted = models.BooleanField()
but I am getting the following errors when running the server:
- >Accessor for field 'target' clashes with related field 'User.gameclaim_set'. Add a related_name argument to the definition for 'target'.
- >Accessor for field 'claimer' clashes with related field 'User.gameclaim_set'. Add a related_name argument to the definition for 'claimer'.
Can you please explain why I am getting the errors and how to fix them?
Python Solutions
Solution 1 - Python
You have two foreign keys to User. Django automatically creates a reverse relation from User back to GameClaim, which is usually gameclaim_set
. However, because you have two FKs, you would have two gameclaim_set
attributes, which is obviously impossible. So you need to tell Django what name to use for the reverse relation.
Use the related_name
attribute in the FK definition. e.g.
class GameClaim(models.Model):
target = models.ForeignKey(User, related_name='gameclaim_targets')
claimer = models.ForeignKey(User, related_name='gameclaim_users')
isAccepted = models.BooleanField()
Solution 2 - Python
The User
model is trying to create two fields with the same name, one for the GameClaims
that have that User
as the target
, and another for the GameClaims
that have that User
as the claimer
. Here's the docs on related_name
, which is Django's way of letting you set the names of the attributes so the autogenerated ones don't conflict.
Solution 3 - Python
The OP isn't using a abstract base class... but if you are, you will find that hard coding the related_name in the FK (e.g. ..., related_name="myname") will result in a number of these conflict errors - one for each inherited class from the base class. The link provided below contains the workaround, which is simple, but definitely not obvious.
From the django docs...
> If you are using the related_name > attribute on a ForeignKey or > ManyToManyField, you must always > specify a unique reverse 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) each time.
More info here.
Solution 4 - Python
Sometimes you have to use extra formatting in related_name
-
actually, any time when inheritance is used.
class Value(models.Model): value = models.DecimalField(decimal_places=2, max_digits=5) animal = models.ForeignKey( Animal, related_name="%(app_label)s_%(class)s_related")
class Meta: abstract = True
class Height(Value): pass
class Weigth(Value): pass
class Length(Value): pass
No clash here, but related_name is defined once and Django will take care for creating unique relation names.
then in children of Value class, you'll have access to:
herdboard_height_related
herdboard_lenght_related
herdboard_weight_related
Solution 5 - Python
I seem to come across this occasionally when I add a submodule as an application to a django project, for example given the following structure:
myapp/
myapp/module/
myapp/module/models.py
If I add the following to INSTALLED_APPS:
'myapp',
'myapp.module',
Django seems to process the myapp.mymodule models.py file twice and throws the above error. This can be resolved by not including the main module in the INSTALLED_APPS list:
'myapp.module',
Including the myapp
instead of myapp.module
causes all the database tables to be created with incorrect names, so this seems to be the correct way to do it.
I came across this post while looking for a solution to this problem so figured I'd put this here :)
Solution 6 - Python
Just adding to Jordan's answer (thanks for the tip Jordan) it can also happen if you import the level above the apps and then import the apps e.g.
myproject/ apps/ foo_app/ bar_app/
So if you are importing apps, foo_app and bar_app then you could get this issue. I had apps, foo_app and bar_app all listed in settings.INSTALLED_APPS
And you want to avoid importing apps anyway, because then you have the same app installed in 2 different namespaces
apps.foo_app
and
foo_app