Error creating several recursive m2m relationships - django

I need to store the relations between people. So I have the following models
class Person(models.Model):
name = models.CharField(max_length=255, blank=True)
parents = models.ManyToManyField('self', through='PersonRelationship', symmetrical=False, blank=True, related_name="person_parents_set")
friends = models.ManyToManyField('self', through='PersonRelationship', symmetrical=False, blank=True, related_name="person_friends_set")
class PersonRelationship(models.Model):
from_person = models.ForeignKey(Person, related_name="from_persons")
to_person = models.ForeignKey(Person, related_name="to_persons")
relation_start = models.DateField(blank=True)
relation_end = models.DateField(blank=True)
When I try to syncdb I get this error:
Error: One or more models did not validate:
films.person: The model Person has two manually-defined m2m relations through the model PersonRelationship, which is not permitted. Please consider using an extra field on your intermediary model instead.
I guess I cannot have two m2m relationships trough the same model, so I tried to create a model for each type of relation, to avoid repeating myself I used a abstract model like this:
class PersonRelationship(models.Model):
from_person = models.ForeignKey(Person, related_name="from_persons")
to_person = models.ForeignKey(Person, related_name="to_persons")
relation_start = models.DateField(blank=True)
relation_end = models.DateField(blank=True)
class Meta:
abstract = True
class PersonParent(PersonRelationship):
pass
class PersonFriend(PersonRelationship):
pass
And I'm getting this error, but I already have a related_name:
films.personparent: Accessor for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
films.personparent: Reverse query name for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
films.personparent: Accessor for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
films.personparent: Reverse query name for field 'from_person' clashes with related field 'Person.from_persons'. Add a related_name argument to the definition for 'from_person'.
Any help would be appreciated.

I just found the solution, I am posting it in case somebody coming from google had found the same issue.
Read this link [link updated to v1.9]:
https://docs.djangoproject.com/en/1.9/topics/db/models/#be-careful-with-related-name
So I just changed the related name to:
from_person = models.ForeignKey(Person, related_name="%(app_label)s_%(class)s_from_persons")
to_person = models.ForeignKey(Person, related_name="%(app_label)s_%(class)s_to_persons")

Related

Django getting error: "Reverse accessor for" in Models

I am trying to create a db model using django inspect db and it is generating all the models but I am getting error.
I am using this command to generate db models for existing database:
python manage.py inspectdb > models.py
It is generating models accurately but in fileds such as this:
create_uid = models.ForeignKey('self', models.DO_NOTHING,db_column='create_uid', blank=True, null=True)
write_uid = models.ForeignKey('self',models.DO_NOTHING, db_column='write_uid', blank=True, null=True)
I am getting error:
polls.ResUsers.create_uid: (fields.E304) Reverse accessor for 'ResUsers.create_uid' clashes with reverse accessor for 'ResUsers.write_uid'.
HINT: Add or change a related_name argument to the definition for 'ResUsers.create_uid' or 'ResUsers.write_uid'.
polls.ResUsers.write_uid: (fields.E304) Reverse accessor for 'ResUsers.write_uid' clashes with reverse accessor for 'ResUsers.create_uid'.
HINT: Add or change a related_name argument to the definition for 'ResUsers.write_uid' or 'ResUsers.create_uid'.
I am adding related names like this:
create_uid = models.ForeignKey('self', models.DO_NOTHING,related_name='create_uid',db_column='create_uid', blank=True, null=True)
What should I do in order to use generated models. I am using postgres.
I am updating my question one of the answer worked for me when I am using it like this:
create_uid = models.ForeignKey(
'self',
models.DO_NOTHING,
db_column='create_uid',
related_name='created_items',
blank=True,
null=True
)
In one other model class when I am using this code like this:
create_uid = models.ForeignKey(
'ResUsers',
models.DO_NOTHING,
db_column='create_uid',
related_name='created_items',
blank=True,
null=True
)
I am getting the error:
polls.ResUsers.create_uid: (fields.E304) Reverse accessor for 'ResUsers.create_uid' clashes with reverse accessor for 'SurveyUserInput.create_uid'.
HINT: Add or change a related_name argument to the definition for 'ResUsers.create_uid' or 'SurveyUserInput.create_uid'.
The related_name=… [Django-doc] is the name of the relation in reverse. So it is meant to access all model objects with as create_uid/write_uid the object. This can result in a QuerySet of zero, one or more elements.
Therefore the related_names of two ForeignKeys to the same model, can not be the same, since that would make the model ambiguous. Since your ForeignKeys refer to the 'self' model, you can not even given these the name of a field that already exists.
You thus might want to give the relations a name like:
class MyModel(models.Model):
create_uid = models.ForeignKey(
'self',
models.DO_NOTHING,
db_column='create_uid',
related_name='created_items',
blank=True,
null=True
)
write_uid = models.ForeignKey(
'self',
models.DO_NOTHING,
db_column='write_uid',
related_name='written_items',
blank=True,
null=True
)

How to specify the many to one models in django?

I'm trying to link two models: Department and User. They have a many-to-one relation.
A department can have only admin (User) and a department can have many users.
A User can only be in one department.
Here is my code
class Department(models.Model):
admin = models.ForeignKey("applications.User", blank=True, null=True, on_delete=models.SET_NULL)
class User(AbstractUser, models.Model):
username = models.CharField(max_length=32, unique=True)
department = models.ForeignKey(Department, null=True, on_delete=models.SET_NULL, related_name="members")
But I'm having this error:
ERRORS:
applications.Department.admin: (fields.E303) Reverse query name for 'Department.admin' clashes with field name 'User.department'.
HINT: Rename field 'User.department', or add/change a related_name argument to the definition for field 'Department.admin'.
I need to keep attributes naming as is.
How to properly fix and model the relation between the tables?
Is django assuming that Department may have many admins?

Django m2m relation of the model with itself with extra attributes

I tried to create a model with a many to many self relation, i put this in my code:
class Person(models.Model):
name = models.CharField(max_length=50)
shape_clm = models.ManyToManyField("self", through='Friend', symmetrical=False)
def __str__(self):
return self.name
class Friend(models.Model):
pers_one = models.ForeignKey(Person)
pers_two = models.ForeignKey(Person)
type = models.CharField(max_length=150)
But when i tried to migrate the model to the DB the following error is raised:
Friend.pers_one: reverse accessor for Friend.pers_one clashes with reverse accessor for Friend.pers_two
I'm using Postgres as DB server, how i can make this m2m relation?
You need to add the related_name keyword argument, otherwise the ORM can't tell how will you refer to either of the fields.
class Friend(models.Model):
pers_one = models.ForeignKey(Person, related_name='pers_ones')
pers_two = models.ForeignKey(Person, related_name='pers_twos')
Add related_name arguments to your ForeignKeys in the Friend ModelClass:
class Friend(models.Model):
pers_one = models.ForeignKey(Person, related_name="friends_one")
pers_two = models.ForeignKey(Person, related_name="friends_two")
type = models.CharField(max_length=150)
For more information about related_name take a look at the docs.

How do I write a Django model with ManyToMany relationsship with self through a Model

I want to have a model with a ManyToMany relationship with itself, I don't know how to write this but I'l try to write some code to illustrate what I want to do.
class Person(models.Model):
name = models.CharField()
occupation = models.CharField()
friends = models.ManyToManyField('self', through = PersonFriends)
My Model that I want the friends to go through
class PersonFriends(models.Model)
???
comment = models.CharField()
In a ManyToMany field with through relationship if the other model's name was "Pet" for example I'd name my fields in that through class person and pet and make them models. ForeignKey(Person) and Pet for example
What to I name my fields in my PersonFriends model for the two person-fields now that they are the same model?
You can do something like this:
class Person(models.Model):
name = models.CharField(max_length = 255)
occupation = models.CharField(max_length = 255)
friends = models.ManyToManyField('self', through = 'PersonFriends',
symmetrical = False)
# ^^^^^^^^^^^
# This has to be false when using `through` models. Or else your
# model will not validate.
class PersonFriends(models.Model):
source = models.ForeignKey(Person, related_name = 'source')
# ^^^^^^^^^^^^
# You need different `related_name` for each when you have
# multiple foreign keys to the same table.
target = models.ForeignKey(Person, related_name = 'target')
comment = models.CharField(max_length = 255)
Everything is described in the official docs for ManyToManyField.through_fields (you can search for 'recursive relationships' phrase there to quickly find what you need):
for django 1.11 you have to specify through and (!) through_fields arguments:
class Person(models.Model):
name = models.CharField(max_length=50)
# note the additional arguments here
friends = models.ManyToManyField(
'self',
# recursive relationships to self with intermediary
# through model are always defined as non-symmetrical
symmetrical=False,
through='PersonFriend',
# this argument is required to define a custom
# through model for many to many relationship to self
# position matters: 1 - source (from), 2 - target (to)
through_fields=('person', 'friend'),
)
class PersonFriend(models.Model):
# required relationship-defining foreign keys
# (note that the order does not matter, it matters
# in 'through_fields' argument in 'friends' field of the 'Person' model)
person = models.ForeignKey(Person, on_delete=models.CASCADE)
friend = models.ForeignKey(Person, on_delete=models.CASCADE)
# additional fields
comment = models.CharField()
Without assuming that friendships are symmetrical. Because Buzz Lightyear might be Woody's friend, but Woody isn't friends with Buzz Lightyear till near the end of the film. You can simplify both models and still have reasonable lookup names. You would of course need to make sure that you define two PersonFriends if it's a good friendship.
class Person(models.Model):
name = models.CharField()
occupation = models.CharField()
class PersonFriends(models.Model):
from_person = models.ForeignKey(Person, related_name='friends_with')
to_person = models.ForeignKey(Person, related_name='friends')
comment = models.CharField()
class Meta:
unique_together = ('from_person', 'to_person')
This has the added bonus of a comment for each direction of the friendship. i.e. Tyrion thinks Sansa is a lovely and intelligent, but lost girl. Whereas Sansa might think that Tyrion is an ugly but clever and kind-hearted kinda guy.
class PersonFriends(models.Model):
from_person = models.ForeignKey(Person, related_name='from_person')
to_person = models.ForeignKey(Person, related_name='to_person')
this is from db table structure of a ManyToMany relation to self from my Model structure. Django defines it like that..

how to design model for my case with django?

Here are two roles: Trainer and Trainee. Trainer may have multiple trainees. While each trainee may have only one trainer or have no trainer.
Here is my model:
class TrainerShip(models.Model):
trainer = models.ForeignKey('Trainer')
trainee = models.ForeignKey(User)
request_date = models.DateTimeField(auto_now_add=True)
accept_date = models.DateTimeField(auto_now_add=True)
expiration_date = models.DateTimeField(auto_now_add=True)
class Trainer(models.Model):
user = models.ForeignKey(User, unique=True)
trainee = models.ManyToManyField(User, through=TrainerShip)
introduction = models.TextField(max_length=500)
certification = models.TextField(max_length=300)
specialties = models.TextField(max_length=300)
contact = models.TextField(max_length=100)
active = models.BooleanField(default=False)
I was getting following error when trying to create db:
shen#shen-laptop:~/django/sutifang$ ./manage.py syncdb
Error: One or more models did not validate:
registration.trainer: Accessor for field 'user' clashes with related m2m field 'User.trainer_set'. Add a related_name argument to the definition for 'user'.
registration.trainer: Accessor for m2m field 'trainee' clashes with related field 'User.trainer_set'. Add a related_name argument to the definition for 'trainee'.
Anyone has the idea to solve this problem? Is there a better way to model this kind of relationship?
The problem is that a Foreign key established a bidirectional relationship. This means you can do User.trainer_set to get all of the Trainer models under a User, which means you have a circular reference back to the user database (getting the Trainer models gets all of its fields, one of those fields being the original User model.
So, to fix this, add a related name argument to the Foreign key to stop this circular dependency:
user = models.ForeignKey(User, unique=True, related_name='traineruser')
You can replace traineruser with something that does not already have a table in the database.