Django隐藏重定向

时间:2014-04-23 23:51:46

标签: python django

我想为应用内重定向创建一个不完全重定向的机制,但只需加载另一个视图功能。所以,让我们说我正在进行localhost:8000/a,django呈现视图和视图的最后一行说

return HttpResponseRedirect('/b')

所以现在我的浏览器会转到localhost:8000/b,django将呈现视图并将其返回给我。

现在我想只在服务器端这样做。因此,当我转到localhost:8000/a并且django决定重定向到/b时,它会呈现/b的视图,将其推送到所有中间件等(因此就像重定向一样)并返回响应任何重定向(如用户所见)。

我已经调用了这样的重定向HttpResponseSmartRedirect,它看起来就像那样:

class HttpResponseSmartRedirect(HttpResponseRedirect):
    pass

现在我想为此创建中间件(作为所有中间件的最后一个运行),process_response上的中间件检查响应是否是类HttpResponseSmartRedirect的实例。现在我的问题是 - 当我遇到这种情况时 - 如何使用url中的视图实际生成响应?我可以使用resolve()中的urlsolvers轻松获取查看功能,但我不知道如何强制它通过所有中间件并创建与我获得的响应完全相同的响应随意重定向。最糟糕的做法是只调用urllib2.get(url),但该行的外观让我想破坏我的电脑。

关于如何在不调用丑陋urllib的情况下做得很好的任何想法?

2 个答案:

答案 0 :(得分:1)

您需要在Django请求处理代码的底部重新注入原始请求。

请求从BaseHandler.get_response的{​​{1}}开始处理。

所以解决方案就像(未经测试!):

django.core.handlers.base

对于实际使用,您需要一些防止重定向循环和无限递归的保护。

或者你可以用不同的方式解决问题 - 让浏览器根据重定向进行重新获取。如果需要隐身,那么使用一些客户端Javascript就可以轻松实现。

答案 1 :(得分:0)

BaseHandler示例(不带重定向的斜杠,请使用它代替CommonMiddleware,Django 2.1):

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