Unique BooleanField value in Django?

前端 未结 13 862
清酒与你
清酒与你 2020-12-07 14:11

Suppose my models.py is like so:

class Character(models.Model):
    name = models.CharField(max_length=255)
    is_the_chosen_one = models.BooleanField()
         


        
13条回答
  •  星月不相逢
    2020-12-07 14:35

    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".

提交回复
热议问题