Suppose my models.py is like so:
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
Trying to make ends meet with the answers here, I find that some of them address the same issue successfully and each one is suitable in different situations:
I would choose:
@semente: Respects the constraint at the database, model and admin form levels while it overrides Django ORM the least possible. Moreover it can probably be used inside a through table of a ManyToManyField in aunique_together situation. (I will check it and report)
class MyModel(models.Model):
is_the_chosen_one = models.NullBooleanField(default=None, unique=True)
def save(self, *args, **kwargs):
if self.is_the_chosen_one is False:
self.is_the_chosen_one = None
super(MyModel, self).save(*args, **kwargs)
@Ellis Percival: Hits the database only one extra time and accepts the current entry as the chosen one. Clean and elegant.
from django.db import transaction
class Character(models.Model):
name = models.CharField(max_length=255)
is_the_chosen_one = models.BooleanField()
def save(self, *args, **kwargs):
if not self.is_the_chosen_one:
# The use of return is explained in the comments
return super(Character, self).save(*args, **kwargs)
with transaction.atomic():
Character.objects.filter(
is_the_chosen_one=True).update(is_the_chosen_one=False)
# The use of return is explained in the comments
return super(Character, self).save(*args, **kwargs)
Other solutions not suitable for my case but viable:
@nemocorp is overriding the clean method to perform a validation. However, it does not report back which model is "the one" and this is not user friendly. Despite that, it is a very nice approach especially if someone does not intend to be as aggressive as @Flyte.
@saul.shanabrook and @Thierry J. would create a custom field which would either change any other "is_the_one" entry to False or raise a ValidationError. I am just reluctant to impement new features to my Django installation unless it is absoletuly necessary.
@daigorocub: Uses Django signals. I find it a unique approach and gives a hint of how to use Django Signals. However I am not sure whether this is a -strictly speaking- "proper" use of signals since I cannot consider this procedure as part of a "decoupled application".