mehmet
mehmet

Reputation: 8144

Two ManyToMany relations to the same model via the same intermediate model in Django

My models:

class Person(SchoolModel):
    first_name = models.CharField(max_length=75)
    last_surname = models.CharField(max_length=75)

    students = models.ManyToManyField('self', through='StudentParent',
        through_fields=('parent', 'student'), related_name='+')
    parents = models.ManyToManyField('self', through='StudentParent',
        through_fields=('student', 'parent'), related_name='+')


class StudentParent(SchoolModel):
    student = models.ForeignKey('Person')
    parent = models.ForeignKey('Person')
    relation = models.CharField(max_length=26)

    class Meta:
        unique_together = ('student', 'parent')

As seen above Person model has two m2m relationships to itself: students, and parents. Each person may have many students on the same Person table, and also many parents.

However, Django does not allow this:

Person: (models.E003) The model has two many-to-many relations through  
the intermediate model 'StudentParent'.

I don't see why Django refuses to do so especially since it does not save or validate m2m fields with custom intermediary tables. On the other hand, I only need to use these fields to retrieve related models more easily. Examples:

person_obj.students.all()
Person.objects.filter(parents__in=another_person_queryset)

So my question is, 1) Is there a way around this issue in Django1.11 (making such 2 m2m fields possible via configuration etc)? 2) is there a way to make this happen for a read only scenario by other means?

Would using a proxy to the intermediary model trick django to make 1) happen? Would using custom managers help make 2) happen? What would be the shortest, neatest path?

Note: I am aware a similar question is asked before, however that is a little different and a little old.

Upvotes: 3

Views: 1686

Answers (1)

mehmet
mehmet

Reputation: 8144

Seems tricking Django via a proxy model works for the purposes I described above (retrieving related data of model instances or within filtering querysets). So the models become:

class Person(SchoolModel):
    first_name = models.CharField(max_length=75)
    last_surname = models.CharField(max_length=75)

    students = models.ManyToManyField('self', through='StudentParentProxy', # << !!!!!!
        through_fields=('parent', 'student'), related_name='+')
    parents = models.ManyToManyField('self', through='StudentParent',
        through_fields=('student', 'parent'), related_name='+')


class StudentParent(SchoolModel):
    student = models.ForeignKey('Person')
    parent = models.ForeignKey('Person')
    relation = models.CharField(max_length=26)

    class Meta:
        unique_together = ('student', 'parent')


class StudentParentProxy(StudentParent):
    class Meta:
        proxy = True  # << !!!!!!

Upvotes: 2

Related Questions