簡體   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