【问题标题】:django urls without a trailing slash do not redirect没有斜杠的 django url 不会重定向
【发布时间】:2010-12-08 11:13:43
【问题描述】:

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

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

该网址适用于mySite.com/cast/mySite.com/cast。但是在计算机 B 上,我有一个类似的 url,如下所示:

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

由于某种原因,在计算机 B 上 url mySite.com/login/ 可以工作,但 mySite.com/login 会挂起并且不会像在计算机 A 上那样直接返回到 mySite.com/login/。我错过了什么吗? url.py 的两个文件在我看来都是一样的。

【问题讨论】:

    标签: python django django-urls


    【解决方案1】:

    或者你可以这样写你的网址:

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

    斜杠后的问号使其在正则表达式中是可选的。如果出于某些原因不想使用 APPEND_SLASH 设置,请使用它。

    【讨论】:

    • 称我为天真 - 但为什么这个答案没有得到一百万个赞和 django 常见问题解答中的条目?
    • 很确定您出于 SEO 原因不想这样做 - 最好重定向到一个规范的 URL,而不是有两个有效的 URL。
    • 如果您使用 Django 创建 RESTful API,当开发人员将数据直接发布到端点 URL 时,这可能是一个很好的解决方案。使用APPEND_SLASH 时,如果他们不小心发送了它而没有尾部斜杠,并且您的 urlconf 带有尾部斜杠,他们会在重定向 POST 请求时收到有关数据丢失的异常。
    • 这个解决方案的问题在于,您在 2 个 url 下提供相同的页面(有和没有尾随 /) - 马虎,对爬虫不利,更难维护,更难迁移到新系统(因为它很容易被忽视)
    • 一个小话题(Django/Python),但作为一个有多年 SEO 经验的人,我可以告诉你,如果你想针对搜索引擎进行优化,你不想要同一个 URL 的 2 个版本. site.com/users 是与 site.com/users/ 不同的网址,这不是您想要的 SEO。您只需要 1 个版本的网址和内容!只选择 1 个版本并确保正确重定向另一个版本。
    【解决方案2】:

    在 settings.py 文件中检查您的 APPEND_SLASH 设置

    more info in the django docs

    【讨论】:

    • "当设置为 True 时,如果请求 URL 与 URLconf 中的任何模式都不匹配并且它没有以斜杠结尾,则向带有斜杠的相同 URL 发出 HTTP 重定向附加。请注意,重定向可能会导致在 POST 请求中提交的任何数据丢失。”。 “只有在安装了 CommonMiddleware 时才使用 APPEND_SLASH 设置……”。对于更清洁的解决方案,我更喜欢 Michael Gendin 的答案。
    • 如果您在 urlpatterns 的最后一个条目中使用额外的“catch all”url,这将不起作用。 @speedplane 的答案即使在这些情况下也能奏效。但是,当然,这更简单,如果没有“catch all” urlpattern 条目,应该使用它。
    【解决方案3】:

    这改进了@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 时非常有用。
    • 这如何与正则表达式一起使用?如果原始 url 与带有客户端名称的正则表达式匹配,例如
    • @NicolòGasparini - 较新版本的 Django 有一个与 redirect 一起使用的 pattern_name arg 以及所有匹配的 url args。
    【解决方案4】:

    我也遇到了同样的问题。我的解决方案是在我的正则表达式的末尾添加一个 (|/)。

    url(r'^artists/(?P[\d]+)(|/)$', ArtistDetailView.as_view()),

    【讨论】:

      【解决方案5】:

      附加斜线不带重定向,在设置中使用它而不是CommonMiddleware,Django 2.1:

      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
      

      【讨论】:

        【解决方案6】:

        我也遇到了同样的问题。在我的情况下,它是 urls.py 中一些旧版本的旧版本,从静态文件之前:

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-10-19
          • 1970-01-01
          • 2016-06-28
          相关资源
          最近更新 更多