julienc
julienc

Reputation: 20335

LocaleMiddleware redirects on a non-i18n url pattern

I'm using Django's LocaleMiddleware to internationalize a part of the website I'm working on. Here is my project's urls.py:

from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns

urlpatterns = patterns('',
    url(r'^api/stuff/(?P<stuff_id>)\d+/$', ApiStuff.as_view()),
)

urlpatterns += i18n_patterns('',
    url(r'^stuff/', DoStuff.as_view()),
)

The problem is, when ApiStuff.as_view() returns a 404 response (other error codes behave as expected), the LocaleMiddleware operates the request to make it redirect to /en/api/stuff/<stuff_id>, even though the /api namespace is clearly not in the i18n_patterns (at the end, it generates a 404 error too, but the content of my original response is lost).

Here is the code of ApiStuff:

import django.http
from django.views.generic import View
from project.stuff.models import Stuff


class ApiStuff(View):

    @staticmethod
    def get(request, *args, **kwargs):
        stuff_id = kwargs['stuff_id']

        try:
            stuff = Stuff.objects.get(pk=stuff_id)
        except Stuff.DoesNotExist:
            return response({"error": "stuff not found"}, 404)

        result = stuff.serialize()
        return response(result)


def response(data, status=200):
    data = json.dumps(data)
    return django.http.HttpResponse(data, status=status, content_type='application/json')

I'm using django 1.6.10 (I know, it's late, but I can't update the version right now).

Am I missing something?

Upvotes: 3

Views: 801

Answers (2)

Ruben Decrop
Ruben Decrop

Reputation: 2179

One can get around this issue by using following url config

urlpatterns += i18n_patterns(
    url(r'^(?!api.*)stuff', DoStuff.as_view()),
)

Upvotes: 0

Risadinha
Risadinha

Reputation: 16666

This is an old bug that has been tracked here:

https://code.djangoproject.com/ticket/17734

The 404 error handler is a default handler of Django. It obviously takes the current language into account in order to translate the "not found" message.

Unless you can upgrade to a newer version you probably need to define your own error handler (including route/url).

EDIT:

As a workaround it might be possible to extend the LocaleMiddleware and maybe also CommonMiddleware. However, it could be that the 404 handler does its magic nevertheless. Might be worth a shot though because it should only require few lines of code.

Citing the ticket:

when you request /api/raising/404/, it is redirecting the user to /en/api/raising/404/ (assuming it detects the language as en). If it tests before redirecting the user if /en/api/raising/404/ is resolvable, it would find out that this would raise a 404 as well and thus would not redirect the user.

EDIT 2:

As an alternative you could simply not use i18n_patterns and just detect/switch the language via browser/cookie/parameter. I did that for a project (which included Django CMS) where I kept running into problems with these URLs. It is definitely not a prerequisite for localized Django sites to use i18n URL patterns. It's just something on top, but not at all necessary. Localization will work just fine without it. If you need help with the middleware for switching languages, drop a comment.

Upvotes: 1

Related Questions