Working with M2M Intermediary Models

In this article, we will learn how to use through for Django many-to-many relationship. A few times in the last month, I’ve run into the need to add some metadata to a Django many-to-many relationship.

Let’s go through an example the existing models:

Person and Group Model

Create a model that matches the existing through table and using Meta.db_table:

Membership Model

Now, we change the many-to-many relationship to use the new model:

Group Model

Now generate a new migration with python manage.py makemigrations. Then we will change it.

The initial migration:

Migration File

We just need to wrap these operations in migrations.SeparateDatabaseAndState to get the models in sync without screwing up the existing database setup. All of the changes above represent state changes:

Migration File

Now you can add fields and create additional migrations as normal.

Admin

Admin should look like this:

Person, Group and Membership Admin

Person Admin

Group Admin

Group Admin

Filtering on through fields

You should be able to filter on the through table fields by using the lowercase name of the through model.

# querysets
Group.objects.filter(membership__invite_reason="foo")
<QuerySet [<Group: Python>]>

Group.objects.filter(membership__invite_reason="bar")
<QuerySet [<Group: Django>]>

Person.objects.filter(membership__invite_reason="foo")
<QuerySet [<Person: Erdi>]>

Person.objects.filter(membership__invite_reason="bar")
<QuerySet [<Person: Erdi>]>

Membership.objects.filter(invite_reason='foo')
<QuerySet [<Membership: Erdi Python>]>

Membership.objects.filter(invite_reason='bar')
<QuerySet [<Membership: Erdi Django>]>

# related manager on instances
person_instance = Person.objects.first()
person_instance.groups.filter(membership__invite_reason='foo')
<QuerySet [<Group: Python>]>
    
group_instance = Group.objects.first()
group_instance.members.filter(membership__invite_reason='foo')
<QuerySet [<Person: Erdi>]>

In this article you’ve learned how to use a through with many-to-many relationship. If you want to see more information on through, you can visit this.