确保Django中的字段始终为空

确保Django中的字段始终为空,django,django-models,Django,Django Models,我有一个父类,它被3个不同的模型扩展。父类有一个名为foo的字段,对于其中一个子类,该字段必须始终为null。我如何确保这一点?现在,我正在使用null=True和editable=False约束。但是,如果在对象创建过程中字段是公开的,则可以通过shell或API规避这些限制 class ThirdSubclass(ParentClass): # Over-ridden field from abstract parent class foo = models.Positive

我有一个父类,它被3个不同的模型扩展。父类有一个名为
foo
的字段,对于其中一个子类,该字段必须始终为null。我如何确保这一点?现在,我正在使用
null=True
editable=False
约束。但是,如果在对象创建过程中字段是公开的,则可以通过shell或API规避这些限制

class ThirdSubclass(ParentClass):
    # Over-ridden field from abstract parent class
    foo = models.PositiveSmallIntegerField(blank=True, null=True, editable=False)

我也在使用PositiveSmallIntegerField,因为我希望为该字段分配尽可能少的空间。不管怎样,我该怎么做?超越保存方法是唯一的选择吗?理想情况下,我会喜欢字段定义中的内容。谢谢

正确的方法取决于您对模型使用的期望。为了提高稳健性,以下是四种可能的方法:

  • 如果所有写入都将通过默认模型表单进行:

    您只需设置一个默认值:

    class ThirdSubclass(ParentClass):
        foo = models.PositiveSmallIntegerField(blank=True, null=True, default=None, editable=False)
    
  • 如果所有写入都将通过使用模型验证(即在
    save()之前调用)

    您可以使用验证器:

    def validate_none(value):
        if value is not None:
            raise ValidationError("...")
    
    class ThirdSubclass(ParentClass):
        foo = models.PositiveSmallIntegerField(blank=True, null=True, default=None, editable=False,
                                               validators=[validate_none])
    
  • 如果所有写入都将通过模型进行:

    您可以覆盖
    save()

  • 如果写入可以来自任何地方(例如,使用或原始SQL):

    您需要一个数据库级别的约束。Django对此没有模型级支持,但您可以通过编写自定义迁移并使用
    RunSQL
    创建约束来创建一个


  • 这些我认为2是标准的,如果你不需要3和4的保护,那就最优雅了。

    < P>这样做的正确方法取决于你如何期望你的模型被使用。为了提高稳健性,以下是四种可能的方法:

  • 如果所有写入都将通过默认模型表单进行:

    您只需设置一个默认值:

    class ThirdSubclass(ParentClass):
        foo = models.PositiveSmallIntegerField(blank=True, null=True, default=None, editable=False)
    
  • 如果所有写入都将通过使用模型验证(即在
    save()之前调用)

    您可以使用验证器:

    def validate_none(value):
        if value is not None:
            raise ValidationError("...")
    
    class ThirdSubclass(ParentClass):
        foo = models.PositiveSmallIntegerField(blank=True, null=True, default=None, editable=False,
                                               validators=[validate_none])
    
  • 如果所有写入都将通过模型进行:

    您可以覆盖
    save()

  • 如果写入可以来自任何地方(例如,使用或原始SQL):

    您需要一个数据库级别的约束。Django对此没有模型级支持,但您可以通过编写自定义迁移并使用
    RunSQL
    创建约束来创建一个


  • 这些,我认为2是标准的,如果你不需要3和4的保护,则是最优雅的。

    我怀疑你可以用字段定义来实现这一点,但是推翻了“代码>模型。SaveE())/代码>应该很好。我怀疑你可以用字段定义来实现这一点,但是要覆盖<代码>模型。应该可以。这是一个很好的答案。我想到了另一个解决办法。基本上,使用
    \u meta.get\u field('foo')。get\u internal\u type()
    ,检查父类
    save()
    方法中
    foo
    字段的字段类型,如果它是PositiveIntegerField,则再次手动将其设置为null。这样,只要字段类型为PositiveIntegerField,它将始终为null。我很想听听你对此的想法。@TahmidKhanNafee:这似乎在功能上等同于重写
    ThirdSubclass.save()
    ,但远没有那么优雅。使用继承的全部目的是将专门的行为放在子类上,而不是打开类型。是的,但是如果有12+个子类需要
    foo
    始终为空会怎么样?如果是这样的话,你会创建一个新的中间类来实现这种行为,并让12+从中下降。基于类的继承并不是解决所有代码重用问题的灵丹妙药,但是如果你打算使用Django的模型继承,你应该坚持这个范例。这是一个很好的答案。我想到了另一个解决办法。基本上,使用
    \u meta.get\u field('foo')。get\u internal\u type()
    ,检查父类
    save()
    方法中
    foo
    字段的字段类型,如果它是PositiveIntegerField,则再次手动将其设置为null。这样,只要字段类型为PositiveIntegerField,它将始终为null。我很想听听你对此的想法。@TahmidKhanNafee:这似乎在功能上等同于重写
    ThirdSubclass.save()
    ,但远没有那么优雅。使用继承的全部目的是将专门的行为放在子类上,而不是打开类型。是的,但是如果有12+个子类需要
    foo
    始终为空会怎么样?如果是这样的话,你会创建一个新的中间类来实现这种行为,并让12+从中下降。基于类的继承并不是解决所有代码重用问题的灵丹妙药,但是如果您要使用Django的模型继承,您应该坚持使用这个范例。