13

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')
5
  • 3
    You cant have same related names. There is no other way around than the one you mentioned. Commented Aug 23, 2018 at 14:36
  • 2
    Although, if you are willing to change your DB Schema, then you can replace fields mother and father with parents as a ManyToManyField and add a type field in Parent model with choices as M or F, corresponding to Mother and Father. Then, you can have the related_name of parents as children. Commented Aug 23, 2018 at 14:38
  • @SachinKukreja: using a many-to-may relation can be an option, it can however require extra logic to enforce that every child has a mother and father (and not zero parents, one parent, two fathers, two mothers, three mothers and two fathers, etc.). Commented Aug 23, 2018 at 14:42
  • 1
    @WillemVanOnsem Yes, that is the disadvantage, only if you weren't expecting a child to have multiple mothers and/or fathers. Commented Aug 23, 2018 at 14:47
  • 2
    @SachinKukreja: I agree, it of course depends a bit on the "scope" of the application. In certain countries children can have more parents (well there are two biological, but even that nowadays might change), but other people can be listed as parents that have the same legal obligations. Commented Aug 23, 2018 at 14:51

1 Answer 1

12

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.