繁体   English   中英

Django:如何在基于类和基于函数的自定义验证器之间做出决定?

[英]Django: How to decide between class-based and function-based custom validators?

这是一个初学者的问题。 我正在开发一个允许用户将视频上传到项目模型(通过 ModelForm)的网站,我想正确验证此文件。 我最初以这种方式声明了该字段:

from django.db import models
from django.core.validators import FileExtensionValidator

def user_directory_path(instance, filename):
    """
    Code to return the path
    """

class Project(models.Model):
    """
    """
    # ...Some model fields...
    # Right now I'm only validating and testing with .mp4 files.
    video_file = models.FileField(
        upload_to=user_directory_path,
        validators=[FileExtensionValidator(allowed_extensions=['mp4'])]
    )

但是我在几个地方读到,最好使用libmagic检查文件的幻数并确保其内容与扩展名和 MIME 类型匹配。 我对此很陌生,所以我可能会弄错一些东西。

我按照验证器参考编写了一个使用magic的自定义验证器。 该文档还讨论了“具有__cal__()方法的类”, 这里最受欢迎的答案使用了基于类的验证器。 文档说这可以“针对更复杂或可配置的验证器”完成,但我不明白什么是具体示例,以及我的基于函数的验证器是否足以满足我的尝试。 我想是的,但我没有经验可以肯定。

这就是我所拥有的。

模型.py

from django.db import models
from .validators import validate_media_file

def user_directory_path(instance, filename):
    """
    Code to return the path
    """

class Project(models.Model):
    """
    """
    # ...Some model fields...
    # Right now I'm only validating and testing with .mp4 files.
    video_file = models.FileField(
        upload_to=user_directory_path,
        validators=[validate_media_file]
    )

validators.py(基本上取自文档中的示例)

import os
import magic

from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _

def validate_media_file(value):
    """
    """
    # Upper case to then see if it's in magic.from_buffer() output
    file_extension = os.path.splitext(value.name)[1].upper()[1:]

    # A list because later I will validate other formats
    if file_extension not in ['MP4']:
        raise ValidationError(
            _('File %(value)s does not contain a valid extension'),
            params={'value': value},
        )

    elif file_extension not in magic.from_buffer(value.read()):
        raise ValidationError(
            _(<appropriate error message>),
            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?

你可以在这里看到不同的品质:

  1. 使用基于类的验证器,您可以使用对象。 对象共享具有不同内部状态的相同功能。 您现在可以设置一个验证器,它会检查字符串是否以“abc”、“123”开头,而无需编写新代码
starts_with_abc = StartsWithValidator('abc')
starts_with_123 = StartsWithValidator('123')
starts_with_whatever = StartsWithValidator('whatever')
  1. 您可以使用继承。 想象一下,您想在其他功能中重用开始验证,您只需从“StartsWithValidator”类继承即可。
class StartsWithABCValidator(StartsWithValidator):
    def __init__(self):
        super().__init__('ABC')

    def __call__(self, value):
        super().__call__(value)
  1. 如果你的验证器做了很多复杂的事情,一个简单的函数可能会导致可读性差的代码。 如果您使用类,则可以封装您的功能并将其组合在一起。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM