没有尾部斜杠的Django URL不会重定向


89

我在两个不同的计算机上有两个应用程序。在计算机A上,urls.py文件中的行如下所示:

(r'^cast/$', 'mySite.simulate.views.cast')

该网址对mySite.com/cast/和都适用mySite.com/cast。但是在计算机BI上,有一个类似的url写成:

(r'^login/$', 'mySite.myUser.views.login')

由于某种原因,计算机B上的url mySite.com/login/可以正常工作,但mySite.com/login会挂起并且不会mySite.com/login/像计算机A上那样直接返回。这两个url.py文件对我来说都一样。

Answers:


103

检查APPEND_SLASHsettings.py文件中的设置

django文档中的更多信息


4
“设置为True时,如果请求URL与URLconf中的任何模式都不匹配,并且不以斜杠结尾,则会将HTTP重定向发送到相同的URL,并附加斜杠。请注意,重定向可能会导致在POST请求中提交的所有数据都会丢失。”。“仅在安装CommonMiddleware时才使用APPEND_SLASH设置...”。我更喜欢Michael Gendin提出的更干净的解决方案。
Wtower

3
如果您在urlpatterns的最后一个条目中使用其他“全部捕获” URL,则此方法不起作用。即使在这些情况下,@ speedplane的答案也将起作用。但是,当然,这比较简单,如果没有“全部捕获” urlpattern条目,则应使用它。
np8

194

或者您可以这样写网址:

(r'^login/?$', 'mySite.myUser.views.login')

斜杠后的问号使它在regexp中成为可选项。如果出于某些原因您不想使用APPEND_SLASH设置,请使用它。


11
叫我天真-但是为什么这个答案没有得到一百万的赞成票,并且在django常见问题中却有一个条目?
Fergal Moran

42
可以肯定的是,出于SEO的原因,您不想这样做-与拥有两个有效URL相比,重定向到规范URL更好。
Brian Frantz

47
如果您要使用Django创建RESTful API,那么当开发人员将数据直接发布到端点URL时,这可能是一个很好的解决方案。使用时APPEND_SLASH,如果他们不小心将其发送而不带斜线,并且您的urlconf是带斜线的,他们将在重定向POST请求时得到有关数据丢失的异常。
OrPo

5
此解决方案的问题在于,您在2个url下提供相同的页面(带有或不带有结尾/)-草率,对爬虫不利,更难维护,更难迁移到新系统(因为它很容易被忽略)
贾阿罗2015年

好答案。我宁愿禁止斜线(因为它表示新内容的开始,而不是某些内容的结束(例如/ etc),但这允许标准(/ view)和非标准(/ view /)。
大卫·贝兹

19

这改善了@Michael Gendin的答案。他的答案使用两个单独的URL为同一页面提供服务。最好login自动重定向到login/,然后将后者用作主页:

from django.conf.urls import patterns
from django.views.generic import RedirectView

urlpatterns = patterns('',
    # Redirect login to login/
    (r'^login$', RedirectView.as_view(url = '/login/')),
    # Handle the page with the slash.
    (r'^login/', "views.my_handler"),
)

当您在结尾处使用一个包含所有内容的URL时非常有用。
thclark '18 -10-17

正则表达式如何工作?如果原始URL正则表达式匹配与例如客户端名称
尼科洛加斯帕里尼

@NicolòGasparini-Django的较新版本具有一个pattern_namearg,该argredirect与所有匹配的url arg一起使用。
Tim Tisdall


1

追加斜线而不进行重定向,请在设置Django 2.1中使用它代替CommonMiddleware:

MIDDLEWARE = [
    ...
    # 'django.middleware.common.CommonMiddleware',
    'htx.middleware.CommonMiddlewareAppendSlashWithoutRedirect',
    ...
]

添加到您的主应用程序目录middleware.py中

from django.http import HttpResponsePermanentRedirect, HttpRequest
from django.core.handlers.base import BaseHandler
from django.middleware.common import CommonMiddleware
from django.conf import settings


class HttpSmartRedirectResponse(HttpResponsePermanentRedirect):
    pass


class CommonMiddlewareAppendSlashWithoutRedirect(CommonMiddleware):
    """ This class converts HttpSmartRedirectResponse to the common response
        of Django view, without redirect.
    """
    response_redirect_class = HttpSmartRedirectResponse

    def __init__(self, *args, **kwargs):
        # create django request resolver
        self.handler = BaseHandler()

        # prevent recursive includes
        old = settings.MIDDLEWARE
        name = self.__module__ + '.' + self.__class__.__name__
        settings.MIDDLEWARE = [i for i in settings.MIDDLEWARE if i != name]

        self.handler.load_middleware()

        settings.MIDDLEWARE = old
        super(CommonMiddlewareAppendSlashWithoutRedirect, self).__init__(*args, **kwargs)

    def process_response(self, request, response):
        response = super(CommonMiddlewareAppendSlashWithoutRedirect, self).process_response(request, response)

        if isinstance(response, HttpSmartRedirectResponse):
            if not request.path.endswith('/'):
                request.path = request.path + '/'
            # we don't need query string in path_info because it's in request.GET already
            request.path_info = request.path
            response = self.handler.get_response(request)

        return response

0

我遇到了同样的问题。在我的情况下,这是urls.py中某个旧版本中staticfiles之前的旧版本的剩余内容:

url(r'^%s(?P<path>.*)$' % settings.MEDIA_URL.lstrip('/'),
    'django.views.static.serve',
    kwargs={'document_root': settings.MEDIA_ROOT}),

MEDIA_URL为空,因此此模式匹配所有内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.