ChatGPT解决这个技术问题 Extra ChatGPT

Django: Why do some model fields clash with each other?

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?

These error messages are really good. They already explain how to fix them. And reading up on **[related_name in the documentation]**(docs.djangoproject.com/en/dev/ref/models/fields/#arguments) will explain why they occur.

C
Community

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()

Good answer, but I don't think you were successful in avoiding rudeness :P The "why" is not obvious unless you are aware of how django works internally.
For someone just learning the framework, this would not be obvious.
Thanks, the error message was not obvious to me either, but your explanation about the reverse relation was very helpful.
Just because the Clash were a good band, doesn't make them a particularly descriptive error message ;)
It should also be mentioned that if you do not need to use the reverse relations for all models. In some cases you might wish the model relation to be one way. In this case you use related_name='+'. This tells Django to create a one way relation and ignore the reverse relation.
s
salmanulfarzy

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.


s
salmanulfarzy

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.


S
Sławomir Lenart

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

J
Jordan Hagan

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 :)


l
lukeaus

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


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now