1

I have a Model with a boolean field named is_active. I want to limit the number of models a user can have where the value of that boolean field is True to 1.

class MyModel(models.Model):
    user = models.ForeignKey(User)
    is_active = models.BooleanField(default=False)
    #...more fields ...

Initially I was just going to add a unique_togeather = ("user", "is_active") entry to Meta -- but of course that will also limit the number of False entries a User can have -- which I need to be unlimited.

Ideally, I'd like to solve this at the database level to prevent race conditions.

The models are being created by Celery tasks importing data using MyModel.objects.get_or_create() -- so it is very possible that a race condition could occur due to the level of concurrency from Celery workers.

erikcw
  • 10,787
  • 15
  • 58
  • 75

1 Answers1

2

You should create custom clean method on your model.

from django.core.exceptions import ValidationError
from django.db import models

class MyModel(models.Model):
    user = models.ForeignKey(User)
    is_active = models.BooleanField(default=False)
    #...more fields ...

    def clean(self):
        if not self.pk and MyModel.objects.filter(user=self.user, is_active=True).exists():
            raise ValidationError('How about no?')
Kamil Rykowski
  • 1,449
  • 13
  • 26
  • 3
    Is there anyway to add a database constraint of some type also (Postgres)? Wouldn't this method still be susceptible to race conditions if two instances of the model are created at the same time? Also the models are being created with MyModel.objects.get_or_create() -- so I don't believe the clean() method is ever called in that case. – erikcw Feb 06 '14 at 16:45