The Python Oracle

Django routing with VueJS single page has unexpected behaviour when there is no trailing slash in the URL

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
and get $2,000 discount on your first invoice
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Breezy Bay

--

Chapters
00:00 Django Routing With Vuejs Single Page Has Unexpected Behaviour When There Is No Trailing Slash In Th
02:11 Accepted Answer Score 0
04:09 Thank you

--

Full question
https://stackoverflow.com/questions/5897...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #django #vuejs #routing #trailingslash

#avk47



ACCEPTED ANSWER

Score 0


The problem is that you have a catch-all in re_path(r'^.*$', views.vue), so if any URL is not matched exactly on the earlier paths, this will be triggered.

Django's CommonMiddleware actually appends a trailing slash and redirect, when it finds a 404 and the URL path does not end in / (depending on the APPEND_SLASH setting), but that's on response.

In you case, you can have a tiny request middleware that appends trailing slash if the request path not end in / e.g.:

from django.shortcuts import redirect

class AppendTrailingSlashOnRequestMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):

        if not request.path.endswith('/'):
            query_string = request.META['QUERY_STRING']
            query_string = f'?{query_string}' if query_string else ''
            to_url = f'{request.path}/{query_string}'
            return redirect(to_url, permanent=True)

        response = self.get_response(request)

        return response

Add the middleware to settings.MIDDLEWARE obviously, preferably put it at the top to prevent unnecessarily processing from other middlewares as we'll be redirecting anyways and processing would be required then as well.


But this has an issue; the data from POST/PUT/PATCH will be lost when doing redirection (here we're doing 301 but similarly applicable for 302. There's Temporary Redirect 307 that can help us in this regard and the good thing is all the regular browsers including IE support this. But Django does not have this out of the box; so we need to implement this ourselves:

from django.http.response import HttpResponseRedirectBase

class HttpTemporaryResponseRedirect(HttpResponseRedirectBase):
    status_code = 307

Now, import that in the middleware, and use it instead of redirect:

class AppendTrailingSlashOnRequestMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):

        if not request.path.endswith('/'):
            query_string = request.META['QUERY_STRING']
            query_string = f'?{query_string}' if query_string else ''
            to_url = f'{request.path}/{query_string}'
            return HttpTemporaryResponseRedirect(to_url)  # here

        response = self.get_response(request)

        return response

N.B: If you want to keep the browser caching facilities for GET, you can redirect to 301/307 based on request.method.