当前位置: 首页 > 工具软件 > Slash > 使用案例 >

Django路由APPEND_SLASH报错 自动补全 "/" 及 trailing_slash的解决方案

柏麒
2023-12-01

首先引用django/middleware/common.py中的简介

"""
"Common" middleware for taking care of some basic operations:

        - Forbid access to User-Agents in settings.DISALLOWED_USER_AGENTS

        - URL rewriting: Based on the APPEND_SLASH and PREPEND_WWW settings,
          append missing slashes and/or prepends missing "www."s.

            - If APPEND_SLASH is set and the initial URL doesn't end with a
              slash, and it is not found in urlpatterns, form a new URL by
              appending a slash at the end. If this new URL is found in
              urlpatterns, return an HTTP redirect to this new URL; otherwise
              process the initial URL as usual.

          This behavior can be customized by subclassing CommonMiddleware and
          overriding the response_redirect_class attribute.
"""

主要内容就是:

如果设置了APPEND_SLASH,并且初始的url没有以斜杠结尾,在urlpatterns中找不到对应的路由与之匹配,这个common的中间件就好通过在结尾加斜线。这样在拼接了 "/" 的链接中找到此对应的urlpatterns,返回指向此新url的http重定向。

 

在rest_framework/routers.py中的107、119、126、140行,我们可以看到

url=r'^{prefix}{trailing_slash}$'
url=r'^{prefix}/{url_path}{trailing_slash}$'
url=r'^{prefix}/{lookup}{trailing_slash}$'
url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$'


都是以 trailing_slash加上$符结尾。

就是不论你是list detail 还是自定义的方法 都会走这个路由匹配。

 

在默认配置下的情况

APPEND_SLASH 是默认为True

也就是按common中间件处理:

比如 我们用了一个ModelViewSet 路由地址是 127.0.0.1:8000/zoo/

我们GET 请求 127.0.0.1:8000/zoo 但是没有匹配到^{prefix}/zoo{trailing_slash}$ 因为没有后面的 / ,由于APPEND_SLASH 为True,所以地址拼接了斜杠 就变成了 127.0.0.1:8000/zoo/ 然后路由匹配到,返回列表接口

我们GET 请求 127.0.0.1:8000/zoo/1 但是没有匹配到 ^{prefix}/zoo/(?P<pk>[^/.]+){trailing_slash}$ 因为没有后面的 / ,由于APPEND_SLASH 为True,所以地址拼接了斜杠 就变成了 127.0.0.1:8000/zoo/1/ 然后路由匹配到,返回详情接口

这样看来,通常情况下是没有问题的。

 

但是如果我们使用的方法不是GET请求  而是 POST、DELETE、PATCH、PUT呢?

直接报错

RuntimeError at /api/musiclibrary/1
You called this URL via PATCH, but the URL doesn't end in a slash and you have APPEND_SLASH set.
 Django can't redirect to the slash URL while maintaining PATCH data. 
Change your form to point to 127.0.0.1:8000/zoo/1/ (note the trailing slash), 
or set APPEND_SLASH=False in your Django settings.

他让我们在链接后面加上 "/" 或者 将APPEND_SLASH改为False

但是改为False一样不起作用啊,匹配不到路由啊

按理说加他这个自动追加斜杠的方法是没问题啊,为什么除了GET方法就不行了呢?

关键就在于前面中间件里面的这句话 return an HTTP redirect to this new URL

重定向啊,只支持GET方法 所以失败了。

解决方案:

from rest_framework.routers import SimpleRouter


class StandardRouter(SimpleRouter):
    def __init__(self, trailing_slash='/?'):
        super(StandardRouter, self).__init__()
        self.trailing_slash = trailing_slash

我们自定义一个路由,继承SimpleRouter ,初始化之后修改他的 trailing_slash 为 /?

这样不就是有斜杠和没有斜杠都可以吗  多简单

然后在你对应的app下的urls下写:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from common.routers import StandardRouter
from zoo.views import ZooViewSet

router = StandardRouter()

router.register(r'zoo', ZooViewSet, basename='zoo')
urlpatterns = router.urls

完美!

 类似资料: