Django 中 3 个表之间的多对多关系

Many-to-many relationship between 3 tables in 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 的数据库 table 如下所示:

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

我想在 project_users field/table 中与 Discipline 模型建立额外的关系。这在 Django 中可能吗?我一直在 Django 中查看 intermediary-manytomany relationships,但这并不是我想要的。在我的应用程序中,有一定数量的学科,我想要实现的是在单个项目中为每个用户提供多个学科。所以像这样:

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

这可能吗?

您可以创建一个模式来引用这三个模型,这实际上是 ManyToManyField 在幕后所做的:在两者之间创建一个模型。

class <strong>UserProjectDiscipline</strong>(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
    )

您现在可以使用 myuser.userprojectdiscipline_set.all()、[=16= 访问 UserAccountProject and/or DisciplineUserProjectDiscipline ] 和 mydiscipline.userprojectdiscipline_set.all().

此外,您可以定义跨越此 table 的 ManyToManyField,这样很容易获得 Discipline 的相关 Project,等等。与:

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

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

然后这些将在 UserProjectDiscipline 的 table 上进行 JOIN 以有效检索给定项目等的用户。如果您需要 UserProjectDiscipline 的对象,您仍然可以使用例如 myproject.userprojectdiscipline_set.all().

如果您因此想要为用户 myuser 给定项目 myproject 三个学科,您可以添加这些学科:

UserProjectDiscipline.objects.bulk_create([
    UserProjectDiscipline(user_account=<em>myuser</em>, project=<em>my_project</em>, discipline=<em>mydiscipline<sub>1</sub></em>),
    UserProjectDiscipline(user_account=<em>myuser</em>, project=<em>my_project</em>, discipline=<em>mydiscipline<sub>2</sub></em>),
    UserProjectDiscipline(user_account=<em>myuser</em>, project=<em>my_project</em>, discipline=<em>mydiscipline<sub>3</sub></em>)
])