pythondjangosatchmo

Keeping original request link between redirects in Django?


I do use the default django.core.context_processors.request template context processor so I can access request instance of HttpRequest in my Django templates.

One use is to retrieve original sender url:

import re

nexturl_re = re.compile('\?next=(.+)$')

@register.simple_tag(takes_context=True)
def get_previous_url(context):
    try:
        return shop_base + \
            nexturl_re.search( context['request'].get_full_path() ).group(1)
    except (IndexError, AttributeError):
        return shop_base + '/'

I do use it to extract an argument from sender url.

The issue is with some views that do http redirects to another views so the original optional parameter after ?next= is lost.

Is there some way how to keep/pass the original url for specific views ? For example following url dispatching of smart.smart_add view does a redirect. It does not accept optional keyword arguments.

from django.conf.urls import patterns

urlpatterns += patterns('satchmo_store.shop.views',
    (r'^add/$', 'smart.smart_add', {}, 'satchmo_smart_add'),

Is there some other way than completely rewrite the original view function ?

Thanks.

Update Based on abstractpaper's answer solved the problem as follows:

  1. Written a middleware class to pass around url arguments for redirect responses:
    import re
    
    nexturlopt_re = re.compile('(\?next=.+)$')
    
    class ForwardUrlArguments(object):
        def process_response(self, request, response):
            if response.status_code in (301, 302, …):
                new_location = response.get('Location')
                if new_location:
                    try:
                        new_location += nexturlopt_re.search(
                                request.get_full_path() ).group(1)
                    except (IndexError, AttributeError):
                        pass
                response['Location'] = new_location
    
            return response
    
  2. In a views file decorate specific methods to apply middleware's response:
    from django.utils.decorators import decorator_from_middleware
    
    forward_urlargs = decorator_from_middleware(ForwardUrlArguments)
    
    @forward_urlargs
    def account_signin(request):
        …
    
    @forward_urlargs
    def cart_smart_add(request):
        …
    
    @forward_urlargs
    def cart_set_quantity(request):
        return cart.set_quantity(request)   # wrapped a library function
    

Solution

  • You can write a Middleware to catch HTTP 301 requests and pass on query parameters.