Case insensitive URLS in Django 3.0?

Viewed 922

Is there a way to have case insensitive URLS with Django 2.0 and up syntax?

For example

path('profile/<str:username>/add/',views.AddFriendRedirect.as_view(),name='add_friend'),

If I did profile/USERNAME, when the username is username in all lowercase, how can I make it so that it is case insensitive? So that even uSErnAmE is valid

I know there are questions and answers out there for the old url syntax, but I would like to know if it is possilbe with the new path syntax

2 Answers

Is there a way to have case insensitive URLS with Django 2.0 and up syntax?

In case the full url should be case insensitive, I don't see any other way than the answer in the linked SO post. But what I gather from OP is that only the username part should be case insensitive. If we follow the solution with regex (?i), this url will also be valid PrOFile/UsERname/AdD.

But it looks that OP only wants username comparison to be case insensitive. With the str converter, whatever is passed in url, will be passed as it is to the view. So in true sense, it is already case-insensitive. The suggested approach here should be that in the view one uses username__iexact to get the user.

But, it we want that the username value passed to the view is in same format as required by the view e.g. lowercase, we can register a custom path converter for this.

Because OP is originally using string converter, we could extend that and override to_python to convert value to lowercase. I am going with lowercase here because in OP it is mentioned that username is in lowercase.

class IStringConverter(StringConverter):

    def to_python(self, value):
        return value.lower()

# once done, register it as:
register_converter(IStringConverter, 'istr')

# and use it as:
path('profile/<istr:username>/add/',views.AddFriendRedirect.as_view(),name='add_friend'),

Another solution is to redirect non-lowercase paths to the lowercase path through a custom middleware.

Here's the middleware you want to add:

from django.contrib.redirects.middleware import RedirectFallbackMiddleware    

class CustomRedirectFallbackMiddleware(RedirectFallbackMiddleware):
    
    def process_response(self, request, response):
        if response.status_code != 404:
            return response

        full_path = request.get_full_path()

        if not full_path.islower():
            return self.response_redirect_class(full_path.lower())
Related