Django- How can I allow only a set number of duplications with UniqueConstraint?


I’m making a webpage – a rental place that can rent movies, music cd’s and books.
I’ve created a model of cd –

class Cd(models.Model):
    ('POP', "POP"),
    ("HIP", "Hip-Hop"),
    ("ROC", "Rock"),
    ("BLU", "Blues"),
    ("SOU", "Soul"),
    ("COU", "Country"),
    ("JAZ", "Jazz"),
    ("CLA", "Classical music"),
cd_genre=models.CharField(max_length=3, choices=CD_GENRE)


cd_rental=models.ForeignKey(Rental, on_delete=models.CASCADE, default=1)

def __str__(self):
       # return self.cd_title, '\n', self.cd_band, '\n'
        return "{} {} {}".format(self.cd_band,self.cd_title,self.cd_genre)

But there is a rule that I have to apply here:

-One band can offer cd’s in up to 2 genres. So let’s say I create a cd of Band1 – Band1 can have cd’s in only 2 genres – f.e rock and blues. I have no idea how to implement that.
I’m thinking about making a constraint, but I don’t know what condition to implement:

UniqueConstraint.condition(fields=['cd_band','cd_genre'],condition=??????, name='unique_cd')

I’ve also thought of restructurizing my entire database – making a separate classes for bands and music genres, and then linking it with foreign keys, setting up validators. I think it should work, but I’d have to put in so much work.
Is there any other way of doing it?


If you want to have the database structured this way, which is IMO not great for manipulation and future features. I’d put the check into save() method. Something like this:

def save(self, *args, **kwargs):
    bands_genres = set(Cd.objects.filter(cd_band=self.cd_band).values_list("cd_genre", flat=True))
    if len(bands_genres) > 2:
        raise SomeException
    super().save(*args, **kwargs)

*Edit: Forgot to add that usually you want to use .distinct() after values_list(), but as I chose to use set() for this solution. It is not needed and has the same effect as distinct().

Answered By – Petr Kučera

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published