如何编写基于类的Django验证器?

时间:2015-08-21 11:19:53

标签: python django validation class oop

我正在使用Django 1.8。

documentation on writing validators有一个基于函数的验证器的示例。它还说明使用类:

  

您还可以将具有__call__()方法的类用于更复杂或可配置的验证器。例如,RegexValidator使用这种技术。如果在验证程序模型字段选项中使用了基于类的验证程序,则应通过添加deconstruct()__eq__()方法确保迁移框架可以对其进行序列化。

  • 基于功能的验证器基于类的优缺点是什么?
  • __call__()用于什么,以及如何使用?
  • deconstruct()用于什么,以及如何使用?
  • __eq__()用于什么,以及如何使用?

一个例子会有所帮助。完整答案也可能值得提交到官方文档中。

谢谢!

3 个答案:

答案 0 :(得分:2)

除了能够从BaseValidator继承之外,选择函数和基于类的验证器可能不一定有重要的倾向。我更喜欢基于类,因为你可以在必要时保持内部状态,而不会让客户端看到它(例如编译的正则表达式,表中预先计算的值,历史记录等)。

__call__方法使对象可调用并允许它对模拟类似函数的行为进行排序(即对象可以像函数一样调用),并且对象&#39 ;将调用s __call__覆盖。它要求您在验证器中实现特殊的__call__(self, ...)方法。

class Callable(object):
    def __call__(self,*args,**kwargs):
        print('Calling', args, kwargs)

>>> c = Callable()
>>> c(2, 3, color='red')
Calling (2, 3) {'color': 'red'}
>>>

deconstruct方法似乎提供了一个点,客户端(即您)可以通过编写自定义实现来覆盖序列化行为。例如,请参阅here。这似乎类似于clean方法,您可以在其中为模型实现自定义输入清理,并在调用full_clean时自动调用(例如,当表单使用is_valid时)。

__eq__允许您在两个本身无法比较的对象之间进行比较。例如,如果您有

class Vector2:
    def __init__(self, x, y):
        self.x = x
        self.y = y

您的__eq__实现可能看起来像这样检查两个矢量对象之间的相等性:

# ...
def __eq__(self, other):
    return self.x == other.x and self.y == other.y

这样,您就可以避免对底层引用进行浅层比较。

答案 1 :(得分:2)

验证器功能的一大优势是它们非常简单。他们只需将一个值作为参数,检查它是否有效,如果不是,则引发ValidationError。您无需担心deconstruct__eq__方法可以使迁移工作。

文档中的validate_even示例比验证程序类简单得多。

def validate_even(value):
    if value % 2 != 0:
        raise ValidationError('%s is not an even number' % value)

如果您还需要通过其他数字检查可分性,那么创建验证器类ValidateDivisibleBy是值得的。然后,您可以使用ValidateDivisibleBy(2)ValidateDivisibleBy(3)等。但很多时候,验证器功能已经足够好了。

答案 2 :(得分:1)

从一开始,几乎没有任何缺点 - 除了实现基于类的验证器可能有些复杂。

但是有一些优点:yon可以在类实例中保存用于将来验证的东西,因此每次验证某些内容时都不会计算它,例如编译的正则表达式模式。您还可以通过将代码扩展到类中的其他方法来创建更复杂的验证器。

此外,您可以使用一些参数构建验证器,这些参数可在稍后的验证过程中使用。

__call__方法是实际验证函数 - 它将被调用为具有相同参数的正常验证函数(以及附加的self参数 - 类的实例,就像在所有方法中一样)。它不是来自django框架,它来自python本身。如果实现了__call__方法,则可以像函数一样调用任何类。 migration serializing中解释了deconstruct方法。 __eq__也来自python本身,每个类都可以拥有它,它只是比较2个对象来检查它们是否相等。