Django m2m relation of the model with itself with extra attributes - django

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.

Related

in django two fields with foreign keys from one model to link two fields from another model

I have a "ModelVoiture" model with a foreign key "type_carburant" field and I can access the "typeCarburant" field of the "Carburant" model. I need to access another field of the same model "Carburant", the field "prixCarburant" from the model "ModelVoiture" but if I add the line
prixCarburant = models.ForeignKey(Carburant, on_delete=models.CASCADE)
i have this error
coutcarbur.ModelVoiture.prixCarburant: (fields.E304) Reverse accessor 'Carburant.modelvoiture_set' for 'coutcarbur.ModelVoiture.prixCarburant' clashes with reverse accessor for 'coutcarbur.ModelVoiture.typeCarburant'.
HINT: Add or change a related_name argument to the definition for 'coutcarbur.ModelVoiture.prixCarburant' or 'coutcarbur.ModelVoiture.typeCarburant'.
coutcarbur.ModelVoiture.typeCarburant: (fields.E304) Reverse accessor 'Carburant.modelvoiture_set' for 'coutcarbur.ModelVoiture.typeCarburant' clashes with reverse accessor for 'coutcarbur.ModelVoiture.prixCarburant'.
HINT: Add or change a related_name argument to the definition for 'coutcarbur.ModelVoiture.typeCarburant' or 'coutcarbur.ModelVoiture.prixCarburant'.
my code in coutcarbur/models.py
class MarqueVoiture(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Carburant(models.Model):
name = models.CharField(max_length=50)
prixCarburant = models.DecimalField(max_digits=6, decimal_places=2)
typeCarburant = models.CharField(max_length=50)
def __str__(self):
return self.name
class ModelVoiture(models.Model):
name = models.CharField(max_length=50)
consolitre = models.DecimalField(
max_digits=6, decimal_places=2)
prixCarburant = models.ForeignKey(Carburant, on_delete=models.CASCADE)
typeCarburant = models.ForeignKey(Carburant, on_delete=models.CASCADE)
marque = models.ForeignKey(MarqueVoiture, on_delete=models.CASCADE)
def __str__(self):
return self.name
how to implement related_name function in template to solve this problem.
I must surely revise the diagram of my models?
thanks for any help.

django admin inline with abstract class and m2m field

This problem almost drives me crazy :(
I was trying to use the StackedInline in admin interface.
The code below is in django documentation.
model.py
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
admin.py
class MembershipInline(admin.StackedInline):
model = Membership
extra = 1
class PersonAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
class GroupAdmin(admin.ModelAdmin):
inlines = (MembershipInline,)
But if the Group is an abstract base class and PublicGroup is subclass that inherits from Group. Membership is used to relate PublicGroup and Person.
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='%(class)s_Membership')
class Meta:
abstract = True
class PublicGroup(Group):
pass
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
after running the command
python manage.py sql test
I got error "AssertionError: ForeignKey cannot define a relation with abstract class Group".
After searching for solution, I know foreign key cannot point to a abstract class. Some solutions recommended to use generic relation. So I change the code again.
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = generic.GenericRelation('Membership')
class Meta:
abstract = True
class PublicGroup(Group):
pass
class Membership(models.Model):
person = models.ForeignKey(Person)
content_type = models.ForieignKey(ContentType)
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
This time the command
python manage.py sql test
returns no error. But I got error when I try to add data on admin interface. The error says Membership is not a foreign key of PublicGroup. StackedInline still doesn't work.
Now I really don't know what to do. Does anyone know how to achieve this function.
Thanks for reading!
Is there any good reason why you use this?
class Meta:
abstract = True
If possible, drop it, and then rebuild your database.
It might be interesting for you to read the answers to this stackoverflow question about the difference between abstract models and regular inheritance.
Your model structure is terrible: a M2M relationship will build a relationship table for both Models you try to connect, just like "Through keyword" in M2M field
As I can see, you just want to build a M2M relation between Person and Model based on Group.
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
type = models.CharField(max_lenght=32) # The Type of Group (Public/Private/etc..)
members = models.ManyToManyField(Person, through='Membership')
class Membership(models.Model):
person = models.ForeignKey(Person)
group = models.ForeignKey(Group)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)

Error creating several recursive m2m relationships

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

Reference Abstract Model in Join Table for Many-to-Many in django

I have the following models, with publication needing a m2m with authors via the join table specified, I have done this but keep getting the error:
Error: One or more models did not validate:
publications.workshop: 'staff' is a manually-defined m2m relation through model AuthorsJoinTable, which does not have foreign keys to Staff and Workshop
publications.technicalreport: 'staff' is a manually-defined m2m relation through model AuthorsJoinTable, which does not have foreign keys to Staff and TechnicalReport
publications.authorsjointable: 'publication' has a relation with model Publication, which has either not been installed or is abstract.
publications.authorsjointable: "unique_together" refers to staff, a field that doesn't exist. Check your syntax.
My models look like:
class Publication(models.Model):
title = models.CharField(max_length=500)
staff = models.ManyToManyField("personnel.Staff", related_name='%(app_label)s_%(class)s_related', through='AuthorsJoinTable')
tag = models.ManyToManyField("Tag", related_name='%(app_label)s_%(class)s_related')
class Meta:
abstract = True
class Workshop(Publication):
location = models.CharField(max_length=100)
workshop_title = models.CharField(max_length=100)
start_date = models.DateField()
end_date = models.DateField()
def __unicode__(self):
return u'%s - %s' % (self.title, self.workshoptitle)
class TechnicalReport(Publication):
published_date = models.DateField()
class AuthorsJoinTable(models.Model):
author = models.ForeignKey("Author", related_name='%(app_label)s_%(class)s_from')
publication = models.ForeignKey("Publication", related_name='%(app_label)s_%(class)s_to')
order = models.IntegerField()
class Meta:
unique_together = ('staff', 'publication')
class Tag(models.Model):
tag_name = models.CharField(max_length=100, primary_key=True)
class Author(models.Model):
name = models.CharField(max_length=100)
biography = models.TextField()
So how can I resolve this problem?
publications.authorsjointable: "unique_together" refers to staff, a field that doesn't exist. Check your syntax.
You can't create a ForeignKey on absract model because that model does not have a table in DB and therefore does not have primary key to reference. So you should make your Publication non-abstract or reference Workshop instead. Other error lines should also be gone after that.

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..