3

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?

julienc
  • 19,087
  • 17
  • 82
  • 82
  • Do you still get the same problem even if you use `get_object_or_404`? I wonder if the system behaves differently if the 404 exception is propagated through the middlewares. – Risadinha Jul 04 '17 at 16:03
  • @Risadinha yes, the redirect is the same with `get_object_or_404` – julienc Jul 04 '17 at 16:07

2 Answers2

1

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.

Risadinha
  • 16,058
  • 2
  • 88
  • 91
  • Actually I saw this ticket too, but I already checked that 1.6.10 was already patched at that time (this version was released in January 2015, and the ticket was closed in 2012) – julienc Jul 04 '17 at 15:29
0

One can get around this issue by using following url config

urlpatterns += i18n_patterns(
    url(r'^(?!api.*)stuff', DoStuff.as_view()),
)
Ruben Decrop
  • 1,979
  • 1
  • 17
  • 9