Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to ensure only one entry is True in a Django model?

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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, the unique_together constraint will likely become deprecated. The documentation advises to use the UniqueConstraint [Django-doc] from Django’s constraint
framework
.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading