【问题标题】:Django URLField with custom scheme带有自定义方案的 Django URLField
【发布时间】:2026-02-19 22:55:01
【问题描述】:

Django 的django.db.models.URLField 使用django.core.validators.URLValidator

class URLField(CharField):
    default_validators = [validators.URLValidator()]

由于没有指定要接受的方案,所以 URLValidator 默认为这个集合:

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

【问题讨论】:

  • 你能发布回溯吗?
  • @OregonTrail 我没有遇到异常,而是在管理界面中输入ssh:// URL 时出现“输入有效的 URL”错误。
  • 你能举一个你正在输入的ssh:// uri 的例子吗?当然更改任何敏感信息
  • 我感觉这里没有产生所有的返回值github.com/django/django/blob/master/django/core/…
  • 这是 Django 的一个已知问题。见code.djangoproject.com/ticket/25594。我会尝试覆盖 forms.URLField 以及 fields.URLField.

标签: django


【解决方案1】:

正如@IainDillingham 在 cmets 中提到的,这是 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

【讨论】:

    最近更新 更多