Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django related_name for field clashes

I am getting a field clash in my models:

class Visit(models.Model):
     user = models.ForeignKey(User)
     visitor = models.ForeignKey(User)

Error: One or more models did not validate:
profiles.visit: Accessor for field 'user' clashes with related field 'User.visit_set'. Add a related_name argument to the definition for 'user'.
profiles.visit: Accessor for field 'visitor' clashes with related field 'User.visit_set'. Add a related_name argument to the definition for 'visitor'.

what would be a sensible 'related_field' to use on visitor field? This model basically represents the visits that take place to a particular user's profile.

Also should I replace any of the ForeignKey's with a ManyToManyField? The logic is a bit confusing.

Edit: This seems to fix it, but I am unsure if it's what I want. :)

 class Visit(models.Model):
      user = models.ForeignKey(User)
      visitor = models.ForeignKey(User, related_name='visitors')
like image 629
TheOne Avatar asked Jan 11 '11 14:01

TheOne


2 Answers

When you have a ForeignKey, it creates a property named with the model name plus _set to the referenced model. The problem here is that both foreign keys want to create a property on User named visit_set. The solution is to add related names that are different for each foreign key.

Usually, I use plurals for related names. In cases like these, I add an "as" clause to the related name:

class Visit(models.Model):
     user = models.ForeignKey(User, related_name="visitsAsUser")
     visitor = models.ForeignKey(User, related_name="visitsAsVisitor")

You don't want a ManyToManyField unless you can have zero or more visitors per Visit, or users per Visit.

like image 147
Mike DeSimone Avatar answered Nov 18 '22 09:11

Mike DeSimone


If a visit is a strong concept in your application, then it might make sense to have it the way you defined: visit consists of a 'user user' and a 'user visitor'.

If, however, a visit is just a way in which users relate among themselves, then perhaps you should have a ManyToMany relation between users. For that purpose you should probably use ManyToManyField.symmetrical in a User Profile (in which you extend the information that comes with auth.models.User).

In any case, regarding the related_name, you may either disable the backwards relation if you won't be accessing the visits from the user, or use a sensible name such as visits_to_self on user and visits_to_others on visitor, which would allow seeing who visited a user by calling user.visits_to_self and who the user visited by user.visits_to_others.

like image 22
Miguel Ventura Avatar answered Nov 18 '22 09:11

Miguel Ventura