Django REST Framework验证错误:'输入有效的URL。'

时间:2018-06-15 21:07:45

标签: python django django-rest-framework

在我的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吗?

1 个答案:

答案 0 :(得分:3)

如果您有自己的正则表达式,为什么不只使用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”的网址

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,谢谢阿拉斯达尔