【问题标题】:Django REST Framework validation error: 'Enter a valid URL.'Django REST Framework 验证错误:“输入有效的 URL。”
【发布时间】:2018-11-25 17:14:00
【问题描述】:

在我的 Django REST Framework 项目中,我有一个模型类用于保存 Django 应用程序将在后台任务中抓取的服务:

class Service(models.Model):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=250)
    root_url =URLField(unique=True)

早些时候,我在本地机器上运行了这些服务和 Django 应用程序。现在我将服务和 Django 应用程序都容器化,并让它们在 Docker 上运行。

所以现在我在添加 dockerized 服务时遇到了问题,因为它的根 URL:http://sensor-service:8080/。抛出的错误是:'Enter a valid URL.'

向我的 Django REST API 进行 POST 以及通过 Django REST 框架提供的 GUI 添加服务时都会出现此问题。

所以,基于https://stackoverflow.com/a/49262127/5433896http://www.django-rest-framework.org/api-guide/serializers/#field-level-validation 我尝试了以下方法。注意:最重要的行是第 5 行:允许主机名后面不跟域和/或 TLD。

models.py:

class DockerServiceDNSUrlsCompatibleURLValidator(URLValidator):
    def __init__(self, schemes=None, **kwargs):
        self.host_re = '(' + self.hostname_re + self.domain_re + self.tld_re \
                        + '|localhost|' \
                        + self.hostname_re + ')'  # <=== added: "hostname not followed by a domain and/or TLD is acceptable"
        self.regex = _lazy_re_compile(r'^(?:[a-z0-9\.\-\+]*)://'  # scheme is validated separately
                                      r'(?:\S+(?::\S*)?@)?'  # user:pass authentication
                                      r'(?:' + self.ipv4_re + '|' + self.ipv6_re + '|' + self.host_re + ')'
                                      r'(?::\d{2,5})?'  # port
                                      r'(?:[/?#][^\s]*)?'  # resource path
                                      r'\Z',
                                      re.IGNORECASE)
        super().__init__(schemes, **kwargs)


class DjangoServiceDNSUrlsCompatibleFormURLField(forms.fields.URLField):
    default_validators = [DockerServiceDNSUrlsCompatibleURLValidator()]


class DjangoServiceDNSUrlsCompatibleURLField(models.URLField):
    default_validators = [DockerServiceDNSUrlsCompatibleURLValidator()]

    def formfield(self, **kwargs):
        return super(DjangoServiceDNSUrlsCompatibleURLField, self).formfield(**{
            'form_class': DjangoServiceDNSUrlsCompatibleFormURLField,
        })


class Service(models.Model):
    name = models.CharField(max_length=50)
    description = models.CharField(max_length=250)
    root_url = DjangoServiceDNSUrlsCompatibleURLField(unique=True)

serializers.py:

class ServiceSerializer(serializers.HyperlinkedModelSerializer):
    validators = [DockerServiceDNSUrlsCompatibleURLValidator()]

    def validate_root_url(self, value):
        DockerServiceDNSUrlsCompatibleURLValidator(value)  # will throw validation exception if value isn't OK.
        return value

但是,错误'Enter a valid URL.' 仍然被抛出。有人看到我的方法有问题吗?或者有没有人——最坏的情况,但仍然可以接受——知道如何在这个字段上完全关闭 URLValidation?

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    如果您有自己的正则表达式,为什么不直接使用 models.CharField 而不是 URLField?喜欢:

    models.py

    phone_regex = RegexValidator(
        regex=r'^\+?(?:\(?[0-9]\)?\x20?){4,14}[0-9]$',
        message="Error....")
    
    class FooModel(models.Model):
        phone = models.CharField("Phone Number", validators=[
                             phone_regex], max_length=26, blank=True, null=True)
    

    顺便说一句,要自定义 URLValidator 接受我在下面使用的不带“http/https”的 url

    models.py

    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)
    
    class FooModel(models.Model):
            website = models.CharField(max_length=200, validators=[OptionalSchemeURLValidator()])
    

    这不会改变上传的值,只是让验证通过。 我在我的 DRF 上试过,它可以工作。

    参考Alasdair's answer,谢谢Alasdair

    【讨论】:

      猜你喜欢
      • 2018-08-01
      • 2015-03-17
      • 2017-01-25
      • 2018-03-28
      • 2020-07-29
      • 1970-01-01
      • 2018-07-24
      • 1970-01-01
      • 2015-10-18
      相关资源
      最近更新 更多