Search code examples
djangodjango-modelsmany-to-manydjango-orm

How can I create and link many-to-many tables in Django?


I am implementing the following schema in a Django app, but I am new to Django's ORM:

meal-menu schema

Briefly, a DayMenu lists multiple MenuItems. (A MenuItem is simply a many-to-many relationship between a DayMenu and a Meal.) Each User selects a MenuItem from the DayMenu. (This choice is represented as a UserItemChoice.)

In our first draft models.py (below), MenuItem is defined as a many-to-many field on the DayMenu model.

from __future__ import unicode_literals

from django.db import models

# Create your models here.

class Meal(models.Model):

    # field options: diet
    MEAT = "MEAT"
    VEGETARIAN = "VEGET"
    HALAAL = "HALAA"

    DIET_CHOICES = (
        (MEAT, "Meat"),
        (VEGETARIAN, "Vegetarian"),
        (HALAAL, "Halaal"),
    )

    # field options: type
    FREE = "FREE"
    PAID = "PAID"
    SKIP = "SKIP"

    TYPE_CHOICES = (
        (FREE, "Free"),
        (PAID, "Paid"),
        (SKIP, "Skip"),
    )

    # fields
    cost = models.IntegerField(default=10)
    description = models.CharField(max_length=120)
    diet = models.CharField(max_length=5, choices=DIET_CHOICES)
    type = models.CharField(max_length=5, choices=TYPE_CHOICES)


class DayMenu(models.Model):

    # fields
    date = models.DateField()
    locked = models.BooleanField(default=False)
    item = models.ManyToManyField(Meal)  # TODO: confirm (replaces MenuItem in schema)


# class UserItemChoice(models.Model):
#
#     # fields
#     user = models.CharField()  # FIXME
#     menuitem = models.CharField()  # FIXME
#     selected = models.BooleanField(default=False)
#     like = models.NullBooleanField(default=None)

How do we define UserItemChoice given that:

  • it is itself a many-to-many relationship
  • it links to a many-to-many field rather than a (explicit) model
  • it would (ideally?) be a many-to-many field on the built-in user table

Solution

  • I think what you want is to define UserItemChoice as a through model of m2m relationship between User and MenuItem. through model is mainly used when you want to define some extra attributes between the m2m relationship.

    Here a user could have multiple MenuItems, but you would also want attributes like selected and like attributes coming with the relationship, but moving these 2 attributes to either model is no good, hence the through is the best solution.

    Check out django doc about through definition and example.