I’m stuck on thinking about implementing a "only one entry might be True for one combination".
A Project has n members (Guards) through an intermediate table.
- every Guard may be member of n Projects
- only one combination of Guard <-> Project is allowed (unique_together)
- a MemberShip might be the ‘Main’ one (is_main)
- BUT: Only one of the memberships may be Main.
Do I oversee something or do I have to implement a custom validation on my own?
To complete this, see the given Model:
class Project(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
shortname = models.CharField(_('shortname'), max_length=50)
description = models.TextField(_('description'), blank=True)
members = models.ManyToManyField(Guard, through='ProjectMembership')
class Meta:
unique_together = ['client', 'shortname']
class ProjectMembership(models.Model):
guard = models.ForeignKey(Guard, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
is_main = models.BooleanField(_('is main project'), default=False)
class Meta:
unique_together = ['guard', 'project']
>Solution :
You can work with a UniqueConstraint [Django-doc] that is filtered:
from django.db.models import UniqueConstraint, Q
class ProjectMembership(models.Model):
guard = models.ForeignKey(Guard, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE)
is_main = models.BooleanField(_('is main project'), default=False)
class Meta:
constraints = [
UniqueConstraint(fields=('guard', 'project'), name='unique_guard'),
UniqueConstraint(fields=('guard',), condition=Q(is_main=True), name='one_main_project_per_guard'),
]
Here we thus ensure that if we filter ProjectMembership for is_main=True, that the set of guards is unique, hence a certain Guard can only occur once for is_main, and this thus means that a Guard has at most one Project for which is_main is True.
Note: As the documentation on
unique_together[Django-doc] says, theunique_togetherconstraint will likely become deprecated. The documentation advises to use theUniqueConstraint[Django-doc] from Django’s constraint
framework.