Django的
django.db.models.URLField
使用
django.core.validators.URLValidator
:
class URLField(CharField):
default_validators = [validators.URLValidator()]
由于它没有指定要接受的方案,因此URLValidator默认为此set:
schemes = ['http', 'https', 'ftp', 'ftps']
我希望我的URLField接受ssh:// URL,所以我尝试了这个:
class SSHURLField(models.URLField):
'''URL field that accepts URLs that start with ssh:// only.'''
default_validators = [URLValidator(schemes=['ssh'])]
但是,当我尝试使用有效的ssh:// URL保存新对象时,我被拒绝了.
如果我跳过从URLField继承并直接从CharField继承,也会发生这种情况:(编辑:实际上,这在我重新创建数据库后确实有用.我不确定为什么前者不起作用.)
class SSHURLField(models.CharField):
'''URL field that accepts URLs that start with ssh:// only.'''
default_validators = [URLValidator(schemes=['ssh'])]
def __init__(self, *args, **kwargs):
kwargs['max_length'] = 64
super(SSHURLField, self).__init__(*args, **kwargs)
当我在测试中直接使用URLValidator时,它可以工作:
def test_url(url):
try:
URLValidator(schemes=['ssh'])(url)
return True
except:
return False
>>> test_url('ssh://example.com/')
True
>>> test_url('http://example.com/')
False
最佳答案 正如@IainDillingham在评论中提到的,这是Django中的一个错误:覆盖子类ModelField的default_validator不一定会覆盖与该基类关联的FormField的default_validator.
对于你的例子,django.db.models.URLField,我们可以看到它的关联表单字段[0]是django.forms.fields.URLField [1].因此,此处的解决方法是还为您的自定义SSHURLField覆盖def formfield(…),以使用相同的验证器引用自定义django.forms.fields.URLField子类,如下所示:
from django.core import validators
from django.db import models
from django.forms.fields import URLField as FormURLField
class SSHURLFormField(FormURLField):
default_validators = [validators.URLValidator(schemes=['ssh'])]
class SSHURLField(models.URLField):
'''URL field that accepts URLs that start with ssh:// only.'''
default_validators = [validators.URLValidator(schemes=['ssh'])]
def formfield(self, **kwargs):
return super(SSHURLField, self).formfield(**{
'form_class': SSHURLFormField,
})
[0] https://github.com/django/django/blob/e17088a108e604cad23b000a83189fdd02a8a2f9/django/db/models/fields/init.py#L2275,L2293
[1] https://github.com/django/django/blob/e17088a108e604cad23b000a83189fdd02a8a2f9/django/forms/fields.py#L650