Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django conditional unique together

I have a model that looks like the following:

class LibraryEntry(models.Model):
  host_lib_song_id = models.IntegerField()
  song = models.CharField(max_length=200)
  artist = models.CharField(max_length=200)
  album = models.CharField(max_length=200)
  owning_user = models.ForeignKey(User)
  is_deleted = models.BooleanField(default=False)

Now, if I so a select where is_deleted=False, the combination of host_lib_song_id and owning_user should be unique. How can I express this?

like image 928
Kurtis Nusbaum Avatar asked Nov 23 '11 16:11

Kurtis Nusbaum


People also ask

What is unique together in Django?

unique_together may be deprecated in the future. This is a list of lists that must be unique when considered together. It's used in the Django admin and is enforced at the database level (i.e., the appropriate UNIQUE statements are included in the CREATE TABLE statement).

What is UniqueConstraint in Django?

UniqueConstraint. condition. A Q object that specifies the condition you want the constraint to enforce. For example: UniqueConstraint(fields=['user'], condition=Q(status='DRAFT'), name='unique_draft_user')


2 Answers

Overriding validate_unique to check the uniqueness if is_deleted is False is more appropriate:

...

def validate_unique(self, exclude=None):
    if not self.is_deleted and \
       LibraryEntry.objects.exclude(pk=self.pk).filter(host_lib_song_id=self.host_lib_song_id, owning_user=self.owning_user).exists():
        raise ValidationError('Some error message about uniqueness required')
    super(LibraryEntry, self).validate_unique(exclude=exclude)
like image 199
Chris Pratt Avatar answered Sep 20 '22 14:09

Chris Pratt


You cannot express this through the Meta.unique_together constraint, but through django's model validation:

class LibraryEntry(models.Model):
    def clean(self):
        from django.core.exceptions import ValidationError
        try:
            # try to find a duplicate entry and exclude 'self'
            duplicate = LibraryEntry.objects.exclude(pk=self.pk)\
                .get(owning_user=self.owning_user, 
                     host_lib_song_id=self.host_lib_song_id,
                     is_deleted=False)
            raise ValidationError('Library Entry already exists!')
        except: LibraryEntry.DoesNotExist:
            # no duplicate found
            pass
like image 39
Bernhard Vallant Avatar answered Sep 19 '22 14:09

Bernhard Vallant