Last active
August 21, 2023 12:47
-
-
Save gregplaysguitar/1440567 to your computer and use it in GitHub Desktop.
Append OR remove slash in django - like APPEND_SLASH but smarter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django import http | |
from django.utils.http import urlquote | |
from django import urls | |
from django.conf import settings | |
from django.utils.deprecation import MiddlewareMixin | |
class AppendOrRemoveSlashMiddleware(MiddlewareMixin): | |
"""Like django's built in APPEND_SLASH functionality, but also works in | |
reverse. Eg. will remove the slash if a slash-appended url won't resolve, | |
but its non-slashed counterpart will. | |
Additionally, if a 404 error is raised within a view for a non-slashed url, | |
and APPEND_SLASH is True, and the slash-appended url resolves, the | |
middleware will redirect. (The default APPEND_SLASH behaviour only catches | |
Resolver404, so wouldn't work in this case.) | |
See gregbrown.co.nz/code/append-or-remove-slash/ for more information.""" | |
def process_request(self, request): | |
"""Returns a redirect if adding/removing a slash is appropriate. This | |
works in the same way as the default APPEND_SLASH behaviour but in | |
either direction.""" | |
# check if the url is valid | |
urlconf = getattr(request, 'urlconf', None) | |
if not _is_valid_path(request.path_info, urlconf): | |
# if not, check if adding/removing the trailing slash helps | |
if request.path_info.endswith('/'): | |
new_path = request.path_info[:-1] | |
else: | |
new_path = request.path_info + '/' | |
if _is_valid_path(new_path, urlconf): | |
# if the new url is valid, redirect to it | |
return http.HttpResponsePermanentRedirect( | |
generate_url(request, new_path)) | |
def process_response(self, request, response): | |
"""If a 404 is raised within a view, try appending/removing the slash | |
(based on the setting) and redirecting if the new url is | |
valid.""" | |
if response.status_code == 404: | |
if not request.path_info.endswith('/') and settings.APPEND_SLASH: | |
new_path = request.path_info + '/' | |
elif request.path_info.endswith('/') and not settings.APPEND_SLASH: | |
new_path = request.path_info[:-1] | |
else: | |
new_path = None | |
if new_path: | |
urlconf = getattr(request, 'urlconf', None) | |
if _is_valid_path(new_path, urlconf): | |
return http.HttpResponsePermanentRedirect( | |
generate_url(request, new_path)) | |
return response | |
def generate_url(request, path): | |
if request.get_host(): | |
new_url = "%s://%s%s" % (request.is_secure() and 'https' or 'http', | |
request.get_host(), | |
urlquote(path)) | |
else: | |
new_url = urlquote(path) | |
if request.GET: | |
new_url += '?' + request.META['QUERY_STRING'] | |
return new_url | |
def _is_valid_path(path, urlconf=None): | |
""" | |
Returns True if the given path resolves against the default URL resolver, | |
False otherwise. | |
""" | |
try: | |
urls.resolve(path, urlconf) | |
return True | |
except urls.Resolver404: | |
return False |
thank you soo much
This is just what we needed. Thank you!
Thanks man!!!
How to implement it.
from django.utils.http import urlquote
ImportError: cannot import name 'urlquote' from 'django.utils.http' (C:\Python311\Lib\site-packages\django\utils\http.py)
I am getting such error
@dhrubkumar50 just use from urllib.parse import quote
instead of urlquote.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Just what I needed. Thanks.