[Django]-Django: How to re-route a request to a different view using middleware

2đź‘Ť

This is not a direct answer to your question (“Reroute a request to a different view”), but maybe this solution could adress your problem.

First, you keep your middleware, but use it only to detect if the visitor is a bot:

def process_request(self, request):     
    request.is_bot = is_bot(request) # assuming you have a function for detecting bots
    return 

Then you create a class based view that call a specific method when request.is_bot is True:

class BotViewMixin(object):

    def dispatch(self, request, **kwargs):

        if request.is_bot:
            return self.handle_bot()
        return super(BotViewMixin, self).dispatch(request, **kwargs)

You can then inherit this view anywhere you need (e.g. for your Home Page View). You just have to create a handle_bot method on your view, that will return your response for bots.

Advantages of this solution:

  • You don’t need to write different views for bots, just create a dedicated method
  • You don’t block other middlewares
  • Your logic stay in your views (and not in your middleware)

This is not tested though, so you may need to adapt the code.

EDIT:

Since you use NewRelic and must use a dedicated view for bots in order to get accurate statistics, this approach won’t work for you.

You can go with the middleware thing, and still get all middlewares working. You just have to put your own middleware last in MIDDLWARE_CLASSES:

MIDDLEWARE_CLASSES = (
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'yourproject.CrawlerDetector',
)

Also, I think you should write two middlewares methods: process_request for detecting bots, and process_view for redirecting bots to dedicated view.

The following code should probably work for your situation:

from django.core.urlresolvers import reverse
class CrawlerDetector(object):

    def process_request(self, request):
        """detect if the user agent is a bot"""
        user_agent = request.META.get('HTTP_USER_AGENT', "")
        request.is_bot = self.is_crawler(user_agent)
        return

    def process_view(request, view_func, view_args, view_kwargs):
        if request.is_bot and request.path == reverse('home_page'):
            return HtmlRendererView().get(request)
        return
👤Agate

0đź‘Ť

My current working solution, while not as clean as Eliot’s suggested solution, looks (basically) like this:

class CrawlerDetector(object):

    # Middleware that detects requests that should be rendered by the HtmlRendererView.
    def process_request(self, request):
        user_agent = request.META.get('HTTP_USER_AGENT', "")
        if not self.is_crawler(user_agent):
            return None
        return HtmlRendererView().get(request)

It has the downside of removing any downstream middleware from the flow, but it does allow me to call my crawler-specific View before the root View is routed to.

👤Andrew Chase

Leave a comment