Самый чистый способ разрешить пустую схему в Django URLField

Я использую Django 2.0 и пытаюсь разрешить пользователям вводить ссылку на свой веб-сайт в django ModelForm. Я хотел бы, чтобы мой URLField проверял URL-адреса, даже если у них нет префикса схемы.

Я прочитал это решение: https://stackoverflow.com/questions/16307055/django-urlfield-http-prefix. Мне интересно, есть ли способ добиться этого без написания собственного регулярного выражения в RegexValidator. Это не похоже на очень СУХОЕ решение для повторения всей логики регулярных выражений, встроенной в URLValidator.

Я хочу сделать что-то вроде следующего:

website = models.CharField(max_length=400, blank=True, null=True, validators=[URLValidator(schemes=['', 'http', 'https', 'ftp', 'ftps'])])

Очевидно, что это не работает из-за того, как метод вызова URLValidator проверяет заданные схемы.

    def __call__(self, value):
        # Check first if the scheme is valid
        scheme = value.split('://')[0].lower()
        if scheme not in self.schemes:
            raise ValidationError(self.message, code=self.code)

Добавление пустой строки в список схем не работает, потому что разделение URL-адреса таким образом возвращает весь URL-адрес (поскольку пользователь обычно не включает ://, если этот пользователь не включает префикс схемы).

Теперь я мог бы подклассировать URLField и перезаписать весь метод вызова, чтобы изменить способ обработки схем, но метод вызова включает в себя все регулярное выражение, так что это кажется не более СУХИМ, чем простое копирование регулярное выражение URLField в мой собственный RegexValidator.

Есть ли более чистый или более "Djangonic" способ добиться этого?


person cmanbst    schedule 23.04.2018    source источник


Ответы (1)


Вы можете создать подкласс URLValidator и префикс бессхемных значений с http:// перед вызовом super(). Это позволяет избежать дублирования кода из URLValidator.

from django.core.validators import URLValidator

class OptionalSchemeURLValidator(URLValidator):
    def __call__(self, value):
        if '://' not in value:
            # Validate as if it were http://
            value = 'http://' + value
        super(OptionalSchemeURLValidator, self).__call__(value)
person Alasdair    schedule 23.04.2018
comment
Это имеет смысл для меня. Я добавил этот код в верхнюю часть моего поля models.py и добавил валидатор в поле веб-сайта в моем определении объекта следующим образом: website = models.CharField(max_length=400, blank=True, null=True, validators=[OptionalSchemeURLValidator]). Тем не менее, я проверил поле с вводом www, и оно подтвердилось. По крайней мере, регулярному выражению URLValidator требуется точка, поэтому кажется, что проверки нет. Я предполагаю, что есть основная проблема в том, как я включаю код. - person cmanbst; 23.04.2018
comment
Вам нужно создать экземпляр URLValidator и OptionalSchemeURLValidator: validators=[OptionalSchemeURLValidator()]). - person Alasdair; 23.04.2018