Reputation: 2084
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?
Upvotes: 6
Views: 2015
Reputation: 1827
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 parameters
fromfull_absolute_path
.ii. Next got exact
redirect_path
of separatedfull_absolute_path
formdjango.contrib.redirects
database.iii. Then appended the
URL parameters
which separated fromfull_absolute_path
is 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.
Upvotes: 7