Django only one default row

Question:

I have a ManyToMany relationship that indicates a Doctor can have many specialties, but only one of them is the PRIMARY one.
I’ve designed a custom M2M class as follows:

class Doctor(models.Model):
account = models.ForeignKey(Account, on_delete=models.CASCADE)
specialty = models.ManyToManyField(Specialty, through='DoctorSpecialty')
.....

class Specialty(models.Model):
title = models.CharField(max_length=45)
.....

class DoctorSpecialty(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
specialty = models.ForeignKey(Specialty, on_delete=models.CASCADE)
default = models.BooleanField(default=True)

The doctor can have many specialties, but only one of them can be the default one. He or she can have many specialties with the default field set as False, but cannot have more than one with the default field set as True

I wanted to do something like this:

class Meta:
    constraints = [
    models.UniqueConstraint(fields=['doctor', 'specialty', 'default'], name='unique specialty')
]

But this will mean that the doctor can have only one specialty as a default one, and only one other as a non default one.

How can we achieve this with the minimum of code?

PS: I could leave it without constraints and try to validate adding new entries by checking if another default specialty exists, but this will add a lot of overhead and exception raising.

Asked By: Kaiss B.

||

Answers:

I think there is no way we can achieve this with built-in functions. So I came up with this solution (since no one else answered):

I created another ForeignKey for the Primary Specialty, and ditched the DoctorSpecialty custom M2M class and left the M2M relationship with Specialty. One doctor can have only one primary specialty, and can also choose additional specialties as secondary. Later on in the views, I can put in place an algorithm to remove the primary specialty from the list of specialties when entering additional ones in case there is an existing primary specialty.

Answered By: Kaiss B.

I think that in your example:

class Meta:
    constraints = [
    models.UniqueConstraint(fields=['doctor', 'specialty', 
'default'], name='unique specialty')
]

the constraint won’t really enforce anything, it will allow each specialty to be a default and not default.

For example: if we have a doc (A) with 2 specialties (1,2) we can have:

A, 1, true

A, 1, false

A, 2, true

A, 2, false

because each one is a unique combination.

By your question, you want to enforce one default per doctor (it doesn’t really matter what’s the specialty) so you can add a unique constraint on doctor and default and enforce only one True:

class Meta:
    constraints = [
    models.UniqueConstraint(fields=['doctor', 'default'], condition=Q(default=True), name='doctor_default')
]
Answered By: Kobi Dadon
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.