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 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.
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