Django's CsrfViewMiddleware fails in conjunction with response generated by middleware - django

My Django application is using a middleware stack containing the CsrfViewMiddleware and an own middleware:
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.transaction.TransactionMiddleware',
'myapp.OwnMiddleware'
)
The basic idea is that if an URL can't be found, i.e. no view function is being found, this error is caught by OwnMiddleware.process_response() which returns an own response if the HTTP status is 404 (and some other conditions are being met).
This works fine, with a single problem: Because no view function is called when an invalid URL (according to URLconf) is provided, CsrfViewMiddleware.process_view() is never called, and thus no CSRF cookie is generated.
Therefore the whole CSRF system does not work and the CSRF token is still set to "NOTPROVIDED" in OwnMiddleware.process_response (which means that {% csrf_token %} generates an empty string instead of the usual hidden form field).
What is the best way to solve this problem, i.e. have OwnMiddleware catch 404s and return another (non-404) response, while still being able to use the CSRF token in these responses?
Thanks in advance.

You can manually run something like:
CsrfViewMiddleware.process_view(request, lambda: your_response, [], {})
P.S. I think it's better to use handler404 to catch 404's

Related

Django: Only a single element gets translated

Porting a Django site from 1.2 to 1.5 on Python 2.6 i ran into problems with internationalization.
The wierd thing is that only one string gets translated in the entire site (Well, almost, the date filter could translate long month names when I tested). Other strings located in the same template doesn't get translated, and all translations are located in a single po/mo file. All translations are there, verified with Poedit and compiled with manage.py compilemessages.
Edit: The reason for the single translated string was that it matched a string in the admin site.
While trying things to get it to work I cleared the LOCALE_PATH, restarted the dev server (manage.py runserver), cleared any browser cache (even though meta-data for the site disables cashing), lo and behold the element is still translated. I verified this by adding the same text again after, and it still gets translated, so no client side caching is involved.
Language switching works as expected and the only translated element is changed to the default language, {{ LANGUAGE_CODE }} confirms this.
I've tried clearing the session data and django cache (which doesn't seem to be used by the dev server).
Can someone guess what's going on here? Isn't there any debug flags to get more extensive logging or something?
A minimal view:
def locale_test(request):
locale = request.GET.get('l', None)
if locale:
translation.activate(locale)
di = {"foobar": _("foobar")}
return render_to_response('locale_test.html',di, context_instance=RequestContext(request))
And corresponding template (locale_test.html):
{% load i18n %}
<p>Language: {{ LANGUAGE_CODE }}</p>
<p>Matching string from admin site that gets translated correctly: {% trans "Log out" %}</p>
<p>Translated in template: {% trans "Foobar" %}</p>
<p>Translated in view: {{ foobar }}</p>
Relevant settings:
USE_I18N = True
USE_L10N = True
LANGUAGES = (
('en', 'English'),
('foo', 'Fooo'),
)
LANGUAGE_CODE = 'en'
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.i18n',
'django.core.context_processors.request',
)
LOCALE_PATHS = ('/path/to/my/locale',)
For reference, these questions didn't help me:
django internationalization and translations issue
Django not translating the site properly
Django i18n does not work
Gah! I got bit by the same issue as this guy :
https://code.djangoproject.com/ticket/18492
Namely that a trailing comma was missing in the LOCALE_PATHS tuple. Too bad Django doesn't raise an error for that.
I had a similar issue that I resolved in making sure that whenever I update the django.po file, I compile it:
./manage.py compilemessages
The translation get done from the compiled file (django.mo) and not the .po file
Generate the translation file: ./manage.py makemessages -a
Translate: manually or using a tool like autotranslate
compile the file: ./manage.py compilemessages
Test to see the changes: not that the default language might be picked first, make sure that you change the language. For example change localhost:8000/en/ to localhost:8000/fr/ or localhost:8000/foo/ depending on the language you want to see
I hope this helps

LocaleMiddleware error when django_language cookie is set

I want to use LocaleMiddleware to obtain the user preferred language in the template tier, showing different content for each language. According to django documentation, LocaleMiddleware does the following:
First, it looks for the language prefix in the requested URL. This is only performed when you are using the i18n_patterns function in your root URLconf. See Internationalization: in URL patterns for more information about the language prefix and how to internationalize URL patterns.
Failing that, it looks for a django_language key in the current user's session.
Failing that, it looks for a cookie. The name of the cookie used is set by the LANGUAGE_COOKIE_NAME setting. (The default name is django_language.)
Failing that, it looks at the Accept-Language HTTP header. This header is sent by your browser and tells the server which language(s) you prefer, in order by priority. Django tries each language in the header until it finds one with available translations.
Failing that, it uses the global LANGUAGE_CODE setting.
It seems to work right when it uses the Accept-Language header. However, when I visit the set_language redirect, LocaleMiddleware starts failing with the following error:
AttributeError at /
'NoneType' object has no attribute '_info'
If I exclude the LocaleMiddleware from the middlewares list or clear the browser cookies, the error doesn't appear anymore till I go again to the set_language redirect.
This is my configuration:
settings.py
LANGUAGE_CODE = 'en-us'
USE_I18N = True
LANGUAGES = (
('en', 'English'),
('es', 'EspaƱol'),
)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
#Uncomment the next line for simple clickjacking protection:
#'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
And the following pattern to the set_language redirect in urls.py:
(r'^i18n/', include('django.conf.urls.i18n')),
I've read some information to similar errors and bugs, but none of them solve my problem. Any clues?
This is Django way of saying "Translations not found for the requested language."
Have you ran compilemessages?

Django Translation - Works with test client but not with browser

I can't figure why the django translation (i18n) doesn't work. I use english in the code and I've written translations for french. Strangely, it works when I use django.test.client.Client but not when I use a web browser.
I've tried to set the Accept-Language to fr in my browser settings and I've also tried to delete the key HTTP_ACCEPT_LANGUAGE from the request header.
I've set the language to fr through the setlang view found in django.conf.urls.i18n.
When I do:
{% load i18n %}
{% get_current_language as LANGUAGE_CODE %}
I successfully get fr, even if the string that should be converted in my page is still in english.
I have this in my settings:
USE_I18N = True
#Probably ignored because of the django_language cookie
LANGUAGE_CODE = 'fr'
MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.transaction.TransactionMiddleware',
'django.middleware.cache.FetchFromCacheMiddleware',
)
I've compiled my translation and they work since I get the expected output when using the test client.
I'm pretty sure the problem is something that the browser send to django that affects the translation, but I can't figure what. I've compared the two and the only references to a language are fr in both version.
Anyone have any suggestion on what I could try?
I did more reseach with the debugger and I found that the catalog in _active doesn't contain my translations when using the browser, but does when using the test client. What could cause that behavior?
Unfortunatelly, while 2016 is coming soon, adding Accept-Language header inside test client still not work. But you can activate language manually. See a code below:
from django.utils.translation import activate
activate('fr')
More details you can read here.
Hope this helps!

How do I tell why Django is ignoring the Accept-Language header?

I have a Django app (on Google App Engine) that I wish to internationalize.
settings.py:
USE_I18N = True
LANGUAGE_CODE = 'en'
# Restrict supported languages (and JS media generation)
LANGUAGES = (
('en', 'English'),
('fr', 'French'),
)
MIDDLEWARE_CLASSES = (
'ragendja.middleware.ErrorMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
# i18n
'django.middleware.locale.LocaleMiddleware',
...
I have generated .po and .mo files for my app in locale/fr/LC_MESSAGES (though not at the global level).
I set my browser Accept-Language heading to "fr" and Django ignores it. When I look at request.LANGUAGE_CODE it is always "en".
I can tell the browser is proper because I visit some other i18n-aware site and it returns French.
How do I find what Django thinks is missing about my setup?
I saw this question and it didn't help me.
I am running Django 1.0 using app engine patch 1.0.2.2 on Google App Engine.
There's a certain order that Django does things in terms of i18n.
First it checks LANGUAGE_CODE. It's the site-wide language and if nothing else is set, this is the language the user gets.
Second, since you've added the LocaleMiddleware, it checks if django_language is set in the user session. I would suggest clearing the session information in the DB or creating a completely new user to try with.
Third, it checks if there's a django_language cookie set (or, actually, the name of the cookie is defined by the LANGUAGE_COOKIE_NAME). I would suggest deleting this cookie.
Fourth, it looks for the Accept-Language HTTP header. Which is where your browser setting comes in.
Good luck!
Taken from this page, you can remove the HTTP_ACCEPT_LANGUAGE from the request and fall back on the LocaleMiddleware:
class ForceDefaultLanguageMiddleware(object):
"""
Ignore Accept-Language HTTP headers
This will force the I18N machinery to always choose settings.LANGUAGE_CODE
as the default initial language, unless another one is set via sessions or cookies
Should be installed *before* any middleware that checks request.META['HTTP_ACCEPT_LANGUAGE'],
namely django.middleware.locale.LocaleMiddleware
"""
def process_request(self, request):
if request.META.has_key('HTTP_ACCEPT_LANGUAGE'):
del request.META['HTTP_ACCEPT_LANGUAGE']

Django 1.1 beta 1 - Flatpages Error, Debug = False, with 404.html

The Django flatpages application has a well-known and oft-discussed-on-the-web bug related to a missing 404.html "Page Not Found" template in your project's templates directory. If you have DEBUG = False in your settings.py file, and you're missing the 404.html file, flatpages will generate a 500 server error instead of loading the flatpage because the project tries to find the 404.html template, and the 500 is generated because it isn't there.
My problem is different than this. I do have a 404.html in my templates directory, hooked into my project, the middleware is hooked up, the SITE_ID is correct for each flatpage, and the templates/flatpages/default.html file exists.
When I try to load any flatpage, I get my custom 404.html error page returned to me. So, the 404 template is working, but the flatpage middleware doesn't seem to be checking the URLs in the flatpage models, before it falls back on the 404.
Has anyone else experienced this and/or found a solution? This is a beta version, so perhaps a solution is in the works as I type. I'm using Django 1.1 beta 1.
Here is my entire MIDDLEWARE_CLASSES:
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware',
'djangodblog.DBLogMiddleware',
'ecomstore.SSLMiddleware.SSLRedirect',
'ecomstore.marketing.urlcanon.URLCanonicalizationMiddleware',
'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
)
I browsed the flatpage sources and solved the same problem by adding a slash to the end of the page URL in the admin area.
I had a similar problem today. After a lot of chekcing I finally fixed it by turning on "Enable comments" (in the admin interface) for the flatpage in question...
On page http://www.petersanchez.com/2007/08/19/django-flatpages-wtf/
Peter Sanchez lists 4 checks to do, but it did not help in my case.