Django URLField喜欢在用户输入的末尾添加一个斜杠(/
),强制所有 URL 都用额外的字符存储,这是错误的。如何停止这种行为并保存用户提交的 URL?
3 回答
检查https://github.com/django/django/blob/master/django/forms/fields.py。to_python
_ URLField
_
您可以看到它url_fields[2] = '/'
几乎在方法末尾有一行to_python
。它在 url 的末尾附加一个斜杠/
。您可以在此行之前将执行此操作的逻辑视为注释。
如果给出了一些查询参数,这个斜杠是必要的。
如果您想避免这种行为,请编写您自己的字段,该字段从您的自定义类扩展URLField
并覆盖to_python
。
我也一直在为此苦苦挣扎,因为它会导致某些网址出现问题。例如,http://www.nasa.gov/mission_pages/kepler/news/kepler-62-kepler-69.html/失败,但它可以在没有斜杠的情况下工作。
为了扩展 akshar 的答案,这里解释了执行此操作的方法。例如,在我的 models.py 文件中定义它并设置url = NoSlashURLField()
而不是models.URLField()
在我的模型中删除斜线:
try:
from urllib.parse import urlsplit, urlunsplit
except ImportError: # Python 2
from urlparse import urlsplit, urlunsplit
class NoSlashURLField(models.URLField):
description = "Remove the goddamn slash"
__metaclass__ = models.SubfieldBase
def __init__(self, *args, **kwargs):
super(NoSlashURLField, self).__init__(*args, **kwargs)
def to_python(self, value):
def split_url(url):
"""
Returns a list of url parts via ``urlparse.urlsplit`` (or raises a
``ValidationError`` exception for certain).
"""
try:
return list(urlsplit(url))
except ValueError:
# urlparse.urlsplit can raise a ValueError with some
# misformatted URLs.
raise ValidationError(self.error_messages['invalid'])
value = super(NoSlashURLField, self).to_python(value)
if value:
url_fields = split_url(value)
if not url_fields[0]:
# If no URL scheme given, assume http://
url_fields[0] = 'http'
if not url_fields[1]:
# Assume that if no domain is provided, that the path segment
# contains the domain.
url_fields[1] = url_fields[2]
url_fields[2] = ''
# Rebuild the url_fields list, since the domain segment may now
# contain the path too.
url_fields = split_url(urlunsplit(url_fields))
# if not url_fields[2]:
# # the path portion may need to be added before query params
# url_fields[2] = '/'
value = urlunsplit(url_fields)
return value
对于那些在他们的站点上使用通常的 Django 管理表单,并且还使用 South 进行 DB 迁移的人,您可能希望使用以下方法而不是 Stonefury 的方法。他的方法改变了模型字段,这让 South 感到困惑,除非你添加一些特殊的代码。下面的方法只改变了管理员代码,让 South 完全不知道。
在您的应用程序中的某处定义此类:
class NoSlashURLFormField(forms.URLField):
def to_python(self, value):
def split_url(url):
"""
Returns a list of url parts via ``urlparse.urlsplit`` (or raises a
``ValidationError`` exception for certain).
"""
try:
return list(urlsplit(url))
except ValueError:
# urlparse.urlsplit can raise a ValueError with some
# misformatted URLs.
raise ValidationError(self.error_messages['invalid'])
if value:
url_fields = split_url(value)
if not url_fields[0]:
# If no URL scheme given, assume http://
url_fields[0] = 'http'
if not url_fields[1]:
# Assume that if no domain is provided, that the path segment
# contains the domain.
url_fields[1] = url_fields[2]
url_fields[2] = ''
# Rebuild the url_fields list, since the domain segment may now
# contain the path too.
url_fields = split_url(urlunsplit(url_fields))
value = urlunsplit(url_fields)
return value
然后编辑您的 admin.py 文件,如下所示:
from your_app.path.to.noslash import NoSlashURLFormField
from django.contrib.admin.widgets import AdminURLFieldWidget
class MyModelAdmin(admin.ModelAdmin):
...
formfield_overrides = {
models.URLField: {
'form_class': NoSlashURLFormField,
# Need to specify the AdminURLFieldWidget here because it would
# otherwise get defaulted back to URLInput.
'widget': AdminURLFieldWidget,
}
}