I recently installed Django's default redirects app on my site using the exact instructions specified:
The app works great when my URL is clean, like so:
Redirect setting: /page/ to /redirect/
When I visit https://www.example.com/page/ => redirects to https://www.example.com/redirect/
However, the redirects don't work when URL parameters are appended to the end of my URL, like so:
Redirect setting: /page/ to /redirect/
When I visit https://www.example.com/page/?url_parameter=true => throws Http404 error (page not found)
Ideally, I'd like my redirects to preserve URL parameters, like so:
Redirect setting: /page/ to /redirect/
When I visit https://www.example.com/page/?url_parameter=true => redirects to https://www.example.com/redirect/?url_parameter=true
Is there a way to force the redirects app to preserve URL parameters per the above?
Django Redirects: A Super Simple Example To avoid hard-coding the URL, you can call redirect() with the name of a view or URL pattern or a model to avoid hard-coding the redirect URL. You can also create a permanent redirect by passing the keyword argument permanent=True .
Using permanent redirects might introduce problems (think about podcast players on your phone that remember such redirects and won't recognize it when you move your static file server).
You can pass positional or keyword argument(s) to the redirect shortcut using the reverse() method and the named url of the view you're redirecting to.
request module. Define a web page URL, suppose this URL will be redirected when you send a request to it. Get the response object. Get the webserver returned response status code, if the code is 301 then it means the URL has been redirected permanently.
1.You need to write your own CustomRedirectFallbackMiddleware by subclass django.contrib.redirects.middleware.RedirectFallbackMiddleware and override process_response method of django.contrib.redirects.middleware.RedirectFallbackMiddleware.
custom_redirect_middleware.py
import urlparse
from django import http
from django.conf import settings
from django.contrib.redirects.models import Redirect
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.redirects.middleware import RedirectFallbackMiddleware
class CustomRedirectFallbackMiddleware(RedirectFallbackMiddleware):
    response_gone_class = http.HttpResponseGone
    response_redirect_class = http.HttpResponsePermanentRedirect
    def process_response(self, request, response):
        if response.status_code != 404:
            return response
        full_path = request.get_full_path() 
        """ 
            Seperate query parameters and url if full absolute path contains 
            query parameters using python urlparse library       
        """
        parsed_url = None
        if "?" in full_path:
            parsed_url = urlparse.urlparse(full_path)
            # Now full path contains no query parameters
            full_path = parsed_url.path
        current_site = get_current_site(request)
        r = None
        try:
            r = Redirect.objects.get(site=current_site, old_path=full_path)
        except Redirect.DoesNotExist:
            pass
        if r is None and settings.APPEND_SLASH and not request.path.endswith('/'):
            try:
                if parsed_url is not None:
                    r = Redirect.objects.get(
                        site=current_site,
                        old_path= full_path + '/',
                        )
                else:
                    r = Redirect.objects.get(
                        site=current_site,
                        old_path=request.get_full_path(force_append_slash=True),
                        )
            except Redirect.DoesNotExist:
                pass
        if r is not None:
            if r.new_path == '':
                return self.response_gone_class()
            #Adding back the query parameters to redirecting path
            if parsed_url is not None:
                new_path_with_query_params = r.new_path + "?" + parsed_url.query
                return self.response_redirect_class(new_path_with_query_params)
            #Handles redirections for urls without query parameters
            return self.response_redirect_class(r.new_path)
        return response
In this CustomRedirectFallbackMiddleware  
i. Simply separated
URL parametersfromfull_absolute_path.ii. Next got exact
redirect_pathof separatedfull_absolute_pathformdjango.contrib.redirectsdatabase.iii. Then appended the
URL parameterswhich separated fromfull_absolute_pathis toredirect_path.
2.Remove 'django.contrib.redirects.middleware.RedirectFallbackMiddleware' from your settings.py and add below line to MIDDLEWARE of settings.py.
# Here base is my Django app name
'base.custom_redirect_middleware.CustomRedirectFallbackMiddleware'
All the bellow cases working very fine.
With no URL parameters.
With one URL paramter.
With more than one URL paramters.
Update: Fixed raising of 404 when URL with no trailing slash.
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With