Отношения "многие ко многим" между 3 таблицами в Django

У меня есть следующие модели:

class Project(models.Model):
    project_name = models.CharField(max_length=50)
    project_users = models.ManyToManyField('Users.UserAccount', related_name='project_users', blank=True)
    ....

class UserAccount(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=30, unique=True)
    ....

class Discipline(models.Model):
    name = models.CharField(unique=True, max_length=27, choices=discipline_choices)

Таблица БД для project_users выглядит следующим образом:

*--------*----------------*---------------------*
|   ID   |   project_id   |   user_account_id   |
*--------*----------------*---------------------*

Я хочу иметь дополнительную связь в project_users поле/таблице с Discipline моделью. Возможно ли это в Django? Я рассматривал в Django отношения посредник-манитомания, но это не совсем то, что мне нужно. В моем приложении есть определенное количество дисциплин, и я пытаюсь добиться того, чтобы дать каждому пользователю несколько дисциплин в одном проекте. Так что что-то вроде этого:

*--------*----------------*---------------------*-------------------*
|   ID   |   project_id   |   user_account_id   |   discipline_id   |
*--------*----------------*---------------------*-------------------*

Возможно ли это?

Вы можете сделать режим, который ссылается на три модели, это фактически то, что ManyToManyField делает за занавесками: создает модель между ними.

class UserProjectDiscipline(models.Model):
    user_account = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
    project = models.ForeignKey(
        Project,
        on_delete=models.CASCADE
    )
    discipline = models.ForeignKey(
        Discipline,
        on_delete=models.CASCADE
    )

Теперь вы можете получить доступ к UserProjectDiscipline в UserAccount, Project и/или Discipline с помощью myuser.userprojectdiscipline_set.all(), myproject.userprojectdiscipline_set.all() и mydiscipline.userprojectdiscipline_set.all().

Кроме того, можно определить ManyToManyFields, которые охватывают эту таблицу, так что легко получить связанные Projects из Discipline и т.д. с помощью:

class Project(models.Model):
    project_name = models.CharField(max_length=50)
    users = models.ManyToManyField(
        'Users.UserAccount',
        through='UserProjectDiscipline',
        related_name='projects',
        blank=True
    )
    disciplines = models.ManyToManyField(
        'Discipline',
        through='UserProjectDiscipline',
        related_name='projects',
        blank=True
    )
    # …

class UserAccount(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(max_length=30, unique=True)
    disciplines = models.ManyToManyField(
        'Discipline',
        through='UserProjectDiscipline',
        related_name='users',
        blank=True
    ) 
    # …

Затем они будут делать JOINs на таблице UserProjectDiscipline для получения эффективных пользователей для данного проекта и т.д. Если вам нужны объекты для UserProjectDiscipline, вы можете использовать, например, myproject.userprojectdiscipline_set.all().

Если вы хотите дать пользователю myuser три дисциплины для данного проекта myproject, вы добавляете их с:

UserProjectDiscipline.objects.bulk_create([
    UserProjectDiscipline(user_account=myuser, project=my_project, discipline=mydiscipline1),
    UserProjectDiscipline(user_account=myuser, project=my_project, discipline=mydiscipline2),
    UserProjectDiscipline(user_account=myuser, project=my_project, discipline=mydiscipline3)
])
Вернуться на верх