4

如何在验证 URLField 之前删除空格?

使用“clean_[fieldname]()”似乎是来自https://docs.djangoproject.com/en/dev/ref/forms/validation/的记录方式,但它不适用于 URLField。我已将其简化为可以在 django shell 中运行的基本测试用例:

class XXXTestModel(models.Model):
    url  = models.URLField('URL',null=True,blank=True)
    name = models.CharField(max_length=200)
class XXXTestForm(ModelForm):
    def clean_url(self):
        return self.cleaned_data['url'].strip()
    def clean_name(self):
        return self.cleaned_data['name'].strip() 
    class Meta:
        model = XXXTestModel
        fields = (
             'url',
        )

从 Django shell 测试:

>>> django.VERSION
(1, 5, 1, 'final', 0)
>>> from xxx import XXXTestForm,XXXTestModel
>>> data = dict(url=' http://www.example.com/ ',name=' example ')
>>> f=XXXTestForm(data)
>>> f.is_valid();f.errors
False
{'url': [u'Enter a valid URL.']}
>>> f.cleaned_data
{'name': example'}

这个问题有很多关于堆栈溢出的问题,但没有一个答案可以指导解决方案。

4

1 回答 1

7

这里的问题是如何django.forms.URLField工作。

django.forms.Field.clean定义为:

def clean(self, value):
    """
    Validates the given value and returns its "cleaned" value as an
    appropriate Python object.

    Raises ValidationError for any errors.
    """
    value = self.to_python(value)
    self.validate(value)
    self.run_validators(value)
    return value

请注意,这to_python是在任何验证之前执行的。这是这里的问题 -django.forms.URLField无法理解您给它的值,因此它产生的值无法通过已经定义为django.forms.URLField(即django.core.validators.URLValidator)一部分的验证器集。

它失败的原因是 django 试图“规范化” URL。这包括诸如"http://"在需要的地方添加之类的东西。当给定您的示例 url 时" http://www.example.com ",django 使用urlparse.urlsplit它来获取 url 的“部分”。然而,前导空格把它弄乱了,整个值变成了path. 因此,django 找到 no scheme,并将 URL 重构为"http:// http://www.example.com ". 然后将其提供给django.core.validators.URLValidator,这显然失败了。

为了避免这种情况,我们需要URLField为我们的表单定义我们自己的

from django import forms

class StrippedURLField(forms.URLField):
    def to_python(self, value):
        return super(StrippedURLField, self).to_python(value and value.strip())

使用它可以确保整个过程都按预期进行,并且我们不需要clean_url方法。(注意:你应该clean_*尽可能使用,但这里不是)

class XXXTestForm(forms.ModelForm):
    url = StrippedURLField(blank=True, null=True)
于 2013-11-15T02:24:43.687 回答