Python Django:如何决定基于类和基于函数的自定义验证器?
这是一个初学者的问题。我正在开发一个网站,允许用户将视频上传到项目模型(通过ModelForm),我想正确验证这个文件。我最初是这样声明字段的: 来自django.db导入模型的Python Django:如何决定基于类和基于函数的自定义验证器?,python,django,Python,Django,这是一个初学者的问题。我正在开发一个网站,允许用户将视频上传到项目模型(通过ModelForm),我想正确验证这个文件。我最初是这样声明字段的: 来自django.db导入模型的 从django.core.validators导入FileExtensionValidator def用户目录路径(实例,文件名): """ 返回路径的代码 """ 类项目(models.Model): """ """ #…一些模型字段。。。 #现在我只使用.mp4文件进行验证和测试。 视频文件=models.File
从django.core.validators导入FileExtensionValidator
def用户目录路径(实例,文件名):
"""
返回路径的代码
"""
类项目(models.Model):
"""
"""
#…一些模型字段。。。
#现在我只使用.mp4文件进行验证和测试。
视频文件=models.FileField(
上传到=用户目录路径,
验证器=[FileExtensionValidator(允许的扩展=['mp4'])]
)
但我在几个地方读到,最好使用libmagic
来检查文件的幻数,并确保其内容与扩展名和MIME类型匹配。我对这个很陌生,所以我可能会弄错一些事情
我按照下面的步骤编写了一个使用magic
的自定义验证器。该文档还讨论了“具有\uuuu cal\uuuu()
方法的类”,而最受欢迎的答案是使用基于类的验证器。文档中说“对于更复杂或可配置的验证器”可以这样做,但我还不知道具体的例子是什么,以及我的基于函数的验证器是否足以满足我的要求。我想是的,但我没有经验可以肯定
这就是我所拥有的
models.py
来自django.db导入模型的
从.validators导入验证\媒体\文件
def用户目录路径(实例,文件名):
"""
返回路径的代码
"""
类项目(models.Model):
"""
"""
#…一些模型字段。。。
#现在我只使用.mp4文件进行验证和测试。
视频文件=models.FileField(
上传到=用户目录路径,
验证程序=[验证\u媒体\u文件]
)
py(基本上取自中的示例)
导入操作系统
进口魔术
从django.core.exceptions导入ValidationError
从django.utils.translation导入gettext\u lazy作为_
def验证_媒体_文件(值):
"""
"""
#大写,然后查看它是否有魔力
文件扩展名=os.path.splitext(value.name)[1].upper()[1:]
#列表,因为稍后我将验证其他格式
如果文件扩展名不在['MP4']中:
引发验证错误(
_(“文件%(值)s不包含有效扩展名”),
params={'value':value},
)
elif文件扩展名不在魔术中。从缓冲区(value.read()):
引发验证错误(
_(),
params={'value':value},
)
迁移就是这样进行的。我还用一个扩展名为.mp4的纯文本文件测试了它,然后用另一个文件(和扩展名)测试了它,它可以正常工作。然而,我想知道,如果使用这个而不是基于类的验证器,我是否遗漏了一些东西,而且,正如标题所说,我应该在什么时候使用验证器,因为我可能会遇到另一种情况,我需要知道它
我知道我没有包括MIME类型;我可以稍后再做
另外一个问题是,当magic.from_buffer()
的输出与扩展名和/或MIME类型不匹配时,适当的错误消息是什么?我想说“文件已损坏”,但我不确定。实际上,这是直接基于幻数的输出吗?何时使用基于类的验证器?
在您的示例中,基于函数的验证器就足够了。如果您需要OOP、类和对象的优点,那么您应该切换到基于类的验证器。
想象一下以下非常虚构的源代码:
class StartsWithValidator():
def __init__(self, starts_with):
self.starts_with = starts_with
def __call__(self, value):
if not str(value).startswith(self.starts_with):
raise ValidationError(
'Your string does not start with: {}!'.format(self.starts_with),
params={'value': value}
)
my_validator = StartsWithValidator('123')
test_string = '123OneTwoThree'
my_validator(test_string) # Will it pass the validator?
你可以在这里看到不同的品质:
如果您需要类的优点——继承等等,那么可以使用基于类的验证器。如果您知道现在不需要它,那么基于函数的验证器就足够了。基本上,具有神奇方法“\uuuu call\uuuu()”的类提供了一个函数通常会提供的接口。您可以像调用函数一样调用此类的对象。如果您稍后注意到,您需要在其他地方的不同修改中使用此功能,那么将其转换为类并没有什么大不了的。在我的例子中,我实际上可以使用一个基于类的验证器,并用每种文件格式实例化它,比如
MediaFormatValidator('MP4')
,MediaFormatValidator('AVI')
,等等,并在\u call\uuuu()
方法中运行相同的代码,前提是magic.from\u buffer()
在其输出字符串中包含此格式,就像MP4格式一样,对吗?尽管如此,即使这是正确的,使用一个列表来查看扩展是否在其中还是足够的。是的,你做对了。我还建议只使用一个简单的函数,直到达到这种实现的限制。您会注意到,当您的代码包含太多if语句时,代码会自动重复(注意Ctrl+C/Ctrl+V)或变得太大。还有很多其他的代码气味,但你会找到自己的方法:-)很好。是的,我看这件事太过分了。
starts_with_abc = StartsWithValidator('abc')
starts_with_123 = StartsWithValidator('123')
starts_with_whatever = StartsWithValidator('whatever')
class StartsWithABCValidator(StartsWithValidator):
def __init__(self):
super().__init__('ABC')
def __call__(self, value):
super().__call__(value)