Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django multiple foreign key, Same related name

I would like to create a model(1) with multiple foreign keys to the same other model(2). I want these foreign keys to have the same related_name because each foreign key will point to difference instances of model(2), because I need one reversed relation for all foreign keys.

Maybe an example will be more explicit :

class Parent(Model):
    name = models.CharField(max_length=100)

class Child(Model):
    name = models.CharField(max_length=100)
    father = models.ForeignKey(Parent, related_name='children')
    mother = models.ForeignKey(Parent, related_name='children')

How can I do that ?

I already know an ugly way to do so :

class Parent(Model):
    name = models.CharField(max_length=100)

    @property
    def children(self):
         # Pick the existing one in fields 'children_1' or 'children_2'

class Child(Model):
    name = models.CharField(max_length=100)
    father = models.ForeignKey(Parent, related_name='children_1')
    mother = models.ForeignKey(Parent, related_name='children_2')
like image 911
RomainD Avatar asked Aug 23 '18 14:08

RomainD


People also ask

Can a Django model have 2 foreign keys?

Your intermediate model must contain one - and only one - foreign key to the source model (this would be Group in our example). If you have more than one foreign key, a validation error will be raised.

What is related name in Django?

The related_name attribute specifies the name of the reverse relation from the User model back to your model. If you don't specify a related_name, Django automatically creates one using the name of your model with the suffix _set. Syntax: field_name = models.Field(related_name="name")

How do I create a one to many relationship in Django?

To handle One-To-Many relationships in Django you need to use ForeignKey . The current structure in your example allows each Dude to have one number, and each number to belong to multiple Dudes (same with Business).


Video Answer


1 Answers

The related_names can not be the same, since this would introduce confusion: an object that is related through the mother is not (exactly) the same as an object related through the father.

You can alter your modeling (for example by introducing a ManyToManyField with the Parent, and for example add extra data in the relation about the sex of the parent). But a disavantage of this approach is that now, you no longer set the cardinality of the relation to 2: it means a Child can (by desing) have zero parents, one parent, two parents, three parents, or more. Furthermore it could be possible that a child has two mothers, or two fathers, or two mothers and three fathers. So it can result in a lot of extra logic to prevent certain cases. Note that in some countries that is possible: in some countries extra people can be listed as "parents", and they have the same legal rights and duties as a parent.

You can however define such property to obtain the children, by making a query to fetch all Child objects where the mother, or the father is self:

from django.db.models import Q

class Parent(Model):
    name = models.CharField(max_length=100)

    @property
    def children(self):
         return Child.objects.filter(Q(mother=self) | Q(father=self))

You could for example name the related names 'father_of' and 'mother_of' such that you can query some_parent.mother_of to obtain children where the some_parent is the mother_of. This could be useful if you for example would want to list a table with mothers and their children, or if you would make an application where it is possible that Parents change gender.

If you however want to have strict Fathers and Mothers, then it might be beneficial to define two separate models. The advantage is that you can both name the related_names 'children' then, and furthermore by design you check that the father of a Child is a male (and similar for a mother being female).

like image 94
Willem Van Onsem Avatar answered Sep 22 '22 19:09

Willem Van Onsem