【问题标题】:Django model booleanfield only 1 True for tableDjango model booleanfield only 1 True for table
【发布时间】:2016-05-16 10:41:33
【问题描述】:

我有模型

class Owner(models.Model):
    name = models.CharField(max_length=10)

class PhoneNumber(models.Model):
    isActive = model.BooleanField(default=False)
    owner = model.ForeignKey('Owner')

我想强制只有一个电话号码处于活动状态,因此如果用户在创建或编辑“非活动”电话号码时不小心将其设置为“活动”并且已经存在另一个“活动”电话号码,则表单不应提交并且将显示一个明确的错误以将“活动”字段更改为 False 和错误文本“请在分配新的活动电话号码之前停用旧的活动电话号码”

我该怎么做?我可以在哪个类的哪个验证方法中轻松检查这个?

谢谢

【问题讨论】:

标签: django


【解决方案1】:
class Owner(models.Model):
    name = models.CharField(max_length=10)

class PhoneNumber(models.Model):
    isActive = models.NullBooleanField(default=None, unique=True)
    owner = model.ForeignKey('Owner')

    def save(self, *args, **kwargs):
        if self.isActive is False:
            self.isActive = None
        super(PhoneNumber, self).save(*args, **kwargs)

【讨论】:

  • 你能提供一些关于你的代码的描述吗?你为什么用NullBooleanField
【解决方案2】:

通常可以通过在模型的 Meta 类中定义 unique_together 来自动完成这样的验证,但在这里这不起作用,因为您可能为每个用户有许多不活动的电话号码。因此,您将需要自定义验证。一种方法是在模型本身的 clean 方法中,当表单被验证时调用。

def clean(self):
    if self.isActive:
        active = PhoneNumber.objects.filter(isActive=True, owner=self.owner)
        if self.pk:
            active = active.exclude(pk=self.pk)
        if active.exists():
            raise ValidationError("An active phone number already exists for this user")

【讨论】:

  • “if self.pk: active = active.exclude(pk=self.pk)”是做什么的?
  • 确保您没有找到电话号码的当前实例(如果之前已保存)。
  • 您不能为活动号码添加另一个模型,与所有者一一对应吗?这将强制执行此规则(我的回答)
【解决方案3】:

没有一种方法可以做到这一点。但我可以建议在模型本身中执行此操作并覆盖 save 方法,如下所示:

class PhoneNumber(models.Model):
    isActive = model.BooleanField(default=False)
    owner = models.ForeignKey('Owner')
    phone_number = odels.CharField(max_length=50)

     class Meta:
        unique_together = ('user', 'phone_number',)

     def save(self, *args, **kwargs):
        if self.id: # to ensure that the object is being updated and is not a new one
             if not self.isActive:
                  check_active_uniquniess = self._meta.model.objects.filter(user = self.user).exclude(id=self.id).count()
                  if check_active_uniquniess:
                         raise ValidationError("Please deactivate the old active PhoneNumber before assigning a new active PhoneNumber")
        super(PhoneNumber, self).save(*args, **kwargs)

我还可以建议覆盖 ModelForm 中的 clean 方法。

【讨论】:

    【解决方案4】:
    class Owner(models.Model):
        name = models.CharField(max_length=10)
    
    class PhoneNumber(models.Model):
        phone_number = model.CharField(max_length=255)
        owner = model.ForeignKey('Owner')
    
    class ActivePhoneNumber(models.Model):
    
        active_phone_number = model.ForeignKey(PhoneNumber)
        owner = model.OneToOneField(Owner)
    

    PhoneNumber 可以为每个所有者保存多个号码,其中 ActivePhoneNumber 每个所有者只能保存一个号码。这将在模型级别强制执行每个用户规则一个活动号码。

    您仍需要提供表格来替换活动号码。比如:

    owner=self.request.user
    new_number = PhoneNumber(owner=owner,phone_number="foobar")
    # or new_number = owner.phone_number_set.get(phone_number="foobar")
    new_number.save()
    owner.active_phone_number.delete()
    new_active = ActivePhoneNumber(owner=owner,active_phone_number=new_number)
    new_active.save()
    

    注意:如果一个电话号码只能由一个所有者使用,则设置:

    active_phone_number = model.OneToOneField(PhoneNumber)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-09-28
      • 2021-06-07
      • 1970-01-01
      • 2011-07-08
      • 1970-01-01
      • 2016-09-02
      • 1970-01-01
      • 2021-10-03
      相关资源
      最近更新 更多