I have the following models:
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)
The DB table for project_users
looks like this:
*--------*----------------*---------------------*
| ID | project_id | user_account_id |
*--------*----------------*---------------------*
I want to have an extra relationship in project_users
field/table with the Discipline
model. Is that possible in Django? I have been looking at intermediary-manytomany relationships in Django, but that's not exactly what I want. In my application, there are a set amount of disciplines, and what I'm trying to achieve is to give each user multiple disciplines in a single project. So something like this:
*--------*----------------*---------------------*-------------------*
| ID | project_id | user_account_id | discipline_id |
*--------*----------------*---------------------*-------------------*
Is this possible?
You can make a mode that refers to the three models, that is in fact what a ManyToManyField
does behind the curtains: creating a model in between.
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
)
You can now access the UserProjectDiscipline
s of a UserAccount
, Project
and/or Discipline
with myuser.userprojectdiscipline_set.all()
, myproject.userprojectdiscipline_set.all()
and mydiscipline.userprojectdiscipline_set.all()
.
Furthermore you can define ManyToManyField
s that span over this table, such that it is easy to obtain the related Project
s of a Discipline
, etc. with:
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
)
# …
These will then make JOINs on the table of the UserProjectDiscipline
to retrieve efficiently users for a given project, etc. If you need objects for the UserProjectDiscipline
, you can still use for example myproject.userprojectdiscipline_set.all()
.
If you thus want to give a user myuser
three disciplines for a given project myproject
, you add these with:
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)
])