我正在使用Django 1.8。
documentation on writing validators有一个基于函数的验证器的示例。它还说明使用类:
您还可以将具有
__call__()
方法的类用于更复杂或可配置的验证器。例如,RegexValidator使用这种技术。如果在验证程序模型字段选项中使用了基于类的验证程序,则应通过添加deconstruct()
和__eq__()
方法确保迁移框架可以对其进行序列化。
__call__()
用于什么,以及如何使用?deconstruct()
用于什么,以及如何使用?__eq__()
用于什么,以及如何使用?一个例子会有所帮助。完整答案也可能值得提交到官方文档中。
谢谢!
答案 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个对象来检查它们是否相等。