How to explicitly set django_language in django session - django

How to explicitly set django_language in Django session?
Thanks a lot...

If you want your users to be able to specify language, make sure that LocaleMiddleware is enabled:
MIDDLEWARE_CLASSES = (
...
'django.middleware.locale.LocaleMiddleware',
...
)
Then Django will look for the user's language preference in that order (see get_language_from_request in trans_real.py):
in request.path_info, if i18n_patterns are used
request.session[settings.LANGUAGE_SESSION_KEY] (DEPRECATED in Django 3.0, removed in Django 4.0)
request.COOKIES[settings.LANGUAGE_COOKIE_NAME]
every language in request.META['HTTP_ACCEPT_LANGUAGE'], until accepted one is found
settings.LANGUAGE_CODE.
As of Django 4.0
The most straightforward way to set language explicitly in Django session is to activate and set the cookie, see the docs:
from django.conf import settings
from django.http import HttpResponse
from django.utils import translation
user_language = 'fr' # example
translation.activate(user_language)
# persist using the cookie
response = HttpResponse(...)
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, user_language)
Before Django 4.0
The most straightforward way to set language explicitly in Django session is to rewrite request.session[settings.LANGUAGE_SESSION_KEY]:
def someview (request):
...
request.session[settings.LANGUAGE_SESSION_KEY] = 'en'
...

And if you will use a version >= Django 1.8. Here it is how we could use that:
from django.utils.translation import LANGUAGE_SESSION_KEY
def someview (request):
...
request.session[LANGUAGE_SESSION_KEY] = 'en'

Consider using django.views.i18n.set_language(). Activate this view by adding the following line to your URLconf:
# This example makes the view available at /i18n/setlang/
url(r'^i18n/', include('django.conf.urls.i18n')),
As a convenience, Django comes with a view,
django.views.i18n.set_language(), that sets a user’s language
preference and redirects to a given URL or, by default, back to the
previous page.
The view expects to be called via the POST method, with a language
parameter set in request. If session support is enabled, the view
saves the language choice in the user’s session. Otherwise, it saves
the language choice in a cookie that is by default named
django_language. (The name can be changed through the
LANGUAGE_COOKIE_NAME setting.)

I think the best way is to follow Django documentation:
in your urls.py file:
urlpatterns = [
# other libraries
path('i18n/', include('django.conf.urls.i18n')),
]
and in your template file (ex: "/core.html") just call de standard "set_language" view. I'll go for a boostrap switcher:
{% load i18n %}
<ul class="navbar-nav">
<li class="dropdown nav-item">
<a href="#" class="dropdown-toggle nav-link" data-toggle="dropdown">
<i class="nc-icon nc-planet"></i>
</a>
<ul class="dropdown-menu">
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for lang in languages %}
<button type="submit"
name="language"
value="{{ lang.code }}"
class="dropdown-item">
{{ lang.name_local }}
</button>
{% endfor %}
</form>
</ul>
</li>
</ul>

Related

Switching Django languages with flags and urls

I am currently having a language switcher in Django based on flags, but where the URL for all languages are the same.
I would now like to change the language switcher so that selecting a flag also redirects the user to a URL prefix (like /en, /es, /fr, etc.) so I easily can send the page in different default languages to different users. Linking to the URL prefix works fine, but how do I easiest redirect the users there when they select flags in the code below?
<div class="navbar-btns ml-3">
<div class="navbar-btns-inner">
<div id="language-switcher" class="navbar-btn collapsed">
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="/" />
<select name="language" onchange="this.form.submit()">
{% for language in request|get_language_info_list_ex %}
<option value="{{ language.code }}" {% if language.is_current %} selected="selected"{% endif %}>
<span class="flag">{{ language.flag }}</span>
{# {{ language.code }} #}
</option>
{% endfor %}
</select>
</form>
</div>
</div>
</div>
On my page I use a simple view and some regex to redirect the users back to the page they was on.
Here is my view
from django.conf import settings
from django.http import HttpResponseRedirect
from yourapp.utils.translation import get_locale_url
def set_language(request, language_code=None):
url = request.META.get('HTTP_REFERER', settings.BASE_URL)
url = get_locale_url(url, language_code)
return HttpResponseRedirect(url)
and my utils.translation.py
import re
from django.conf import settings
from django.utils.translation import get_language
def get_locale_url(url, language_code):
pattern = r'^(?:/)|^#$|(?:(?:https?://)?(?:yoursubdomain\.)?domain\.com/?(?:(?:sma|en)?/?)?)'
if settings.USE_I18N:
if any(language_code in language for language in settings.LANGUAGES):
if re.match(pattern, url, flags=re.I):
split_url = re.split(pattern, url, flags=re.I)
if language_code == "nb":
url = settings.BASE_URL + "/" + split_url[len(split_url)-1]
else:
url = settings.BASE_URL + "/" + language_code + "/" + split_url[len(split_url)-1]
return url
Change yoursubdomain (usually www) and yourdomain to work with your own site. You also neeed to add the language codes you have activated to your regex pattern. I use sma and en so I've written (sma|en).
It ain't the prettiest solution, but it works.

How to render templates dynamically for a static user choice

I don't know how to put this question as a title. But my question is I have 2 templates for each view in my django project templates folder. One template for english language and another for spanish language. My templates structure is
Project
|
app
|
templates
|
app
|
home_en.html
home_es.html
about_en.html
about_es.html
I need to render the templates according to the user choice of language. I have the project now fully in english running. As a start I only have the templates converted to spanish and ready to render. I am sorry this is a vague question but some directions to this problem would help.
My main urls are
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^en/', include('app.urls')),
url(r'^es/', include('app.urls')),
]
my app urlpatterns are
urlpatterns = [
url(r'^about$', views.about, name='about'),
url(r'.*', views.home, name='home'), ]
I also tried checking the request url with /en/ or /es/ and then render according to it in each views like below.
def home(request):
if request.path == '/en/':
return render(request, 'app/home_en.html', {'title':'HOME'})
else:
return render(request, 'app/home_es.html', {'title':'HOME'})
def about(request):
if request.path == '/en/about':
return render(request, 'app/about_en.html', {'title':'ABOUT'})
else:
return render(request, 'app/about_es.html', {'title':'ABOUT'})
This works fine when I explicitly give url request as /en/ or /es/. How could i set it on the url based on the users selection of language ?
If I explicitly make request to http://127.0.0.1/es/about, my about page is shown in spanish but when I switch to home from there, it goes back to English home page. I want the url to stay as /es/ as the start even if I change the url. Now it changes to english since it is upper level in pattern
A very simple solution is to use a single pattern with a named group:
url(r'^(?P<language>en|es)/', include('app.urls'))
Your views must then accept the language parameter:
def home(request, language):
# language is either "es" or "en".
return render(request, 'app/home_{}.html'.format(language), {'title': 'HOME'})
You may also consider Django's localization and avoid duplicating the views.
Please read Django translation docs. here: https://docs.djangoproject.com/en/1.10/topics/i18n/translation/#module-django.conf.urls.i18n
See the part: Language prefix in URL patterns
in your urls.py:
from django.conf.urls.i18n import i18n_patterns
urlpatterns += i18n_patterns (
url(r'^about$', views.about, name='about'),
url(r'.*', views.home, name='home'),
)
This will automatically prefix you urls with language codes.
in the views.py you can get language code fomr request.LANGUAGE_CODE like this: from request.LANGUAGE_CODE == 'en'
To choose language put in your html templates:
{% load i18n %}
<form action="{% url 'set_language' %}" method="POST">{% csrf_token %}
<select name="language" id="language">
<option value="en">en</option>
<option value="ru">ru</option>
<option value="az">az</option>
</select>
<button type="submit">send</button>
</form>
or
{% load i18n %}
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>

Unable to set language after using "i18n_pattern" to show language prefix in URL

As suggested, I'm wanting to show a language prefix in the URL and allow a visitor to my site to change the language using a form in the template. I've been using the sections on URL prefix and set_language redirect view from the "Translation" page of the Django docs as a guide so far. My code is largely copied from this source.
The Problem
Without using "i18n_pattern" (having both "url" calls in "pattern") in my URLconf, I manage to select language on the index.html page and have Django redirect me to the same page with the new language I have chosen. However, of course, the language URL prefix isn't shown.
When I use "i18n_pattern", the language prefix appears in the URL but seems to break the ability to change languages from the index.html form. For example, if I'm set on English and I change from "English (en)" to "Türkçe (tr)" in the form, the page essentially does a refresh without changing to Turkish (English is still shown). I can however change the language by changing my URL language prefix from "/en/" to "/tr/".
pages/templates/pages/index.html:
{% load i18n %}
<html>
<head>
...
</head>
<body>
<form action="{% url 'set_language' %}" method="post">
{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
...
</body>
</html>
[project_name]/urls.py:
from django.conf.urls import patterns, include, url
from django.conf.urls.i18n import i18n_patterns
urlpatterns = patterns('',
url(r'^i18n/', include('django.conf.urls.i18n')),
)
urlpatterns += i18n_patterns('',
url(r'', include('pages.urls', namespace='pages')),
)
Note: The templates I'm using are located in the app called "pages".
Any help on getting these to work together would be appreciated! I have so far been unable to find anything on stackoverflow relating to this issue. If any more information is needed, please ask!
This StackOverflow question contains further details and some possible answers to the problem. None of the solutions are really appealing; nor should really be required. Unfortunately, this seems to be a problem with Django where both desired "features" can't work together "out-of-the-box" with the desired effect. In my case, since my site is a single page site, I can get away with setting the context variable with "redirect_to" = '/' (in the view) to negate the problem.

csrf_exempt not working with django auth

I am making the backend for a mobile app and using Django with Userena for the user management. I made the sign in and sign up using Django REST framework and everything works fine. The only thing I need to do now is to implement the "forget password" functionality. I wanted to use the already implemented one from Userena, but I cannot get rid of the error "CSRF token missing or incorrect" even after using the csrf_exempt dectorator. What am I doing worng?
urls.py
from django.contrib.auth.views import password_reset
from django.views.decorators.csrf import csrf_exempt
...
urlpatterns = patterns(
'',
url(r'^password/mobile/reset/$',
csrf_exempt(password_reset),
{'template_name': 'userena/password_reset_form.html',
'email_template_name': 'userena/emails/password_reset_message.txt',
'extra_context': {'without_usernames': userena_settings.USERENA_WITHOUT_USERNAMES}
},
name='userena_password_mobile_reset'),
)
passowrd_reset_form.html
{% extends 'userena/base_userena.html' %}
{% load i18n %}
{% block title %}{% trans "Reset password" %}{% endblock %}
{% block content %}
<form action="" method="post">
<fieldset>
<legend>{% trans "Reset Password" %}</legend>
{% csrf_token %}
{{ form.as_p }}
</fieldset>
<input type="submit" value="{% trans "Send password" %}" />
</form>
{% endblock %}
If you do a GET request before POSTing to the password reset view, you get the CSRF token in a cookie, which you can then send in your POST request.
If you insist on exempting the view: I think the problem lies in the way the CSRF protection is applied to the password_reset view. It is explicitly decorated by csrf_protect.
To have a closer look at the problem, lets assume original_password_reset_view is password_reset without the csrf_protect. Basically, you are doing this:
csrf_exempt(csrf_protect(original_password_reset_view))
# ^^ your code
# ^^ the decorator in django.contrib.auth.views
And adding in the effect of the CsrfViewMiddleware, we get the equivalent of
csrf_protect(csrf_exempt(csrf_protect(original_password_reset_view)))
csrf_protect is just a middleware-turned-decorator from CsrfViewMiddleware. csrf_exempt on the other hand simply sets csrf_exempt=True on its argument. So the middleware, represented by the outer csrf_protect, sees the csrf_exempt=True value on the view and disables its CSRF projection. It negates the outer csrf_protect. So we have:
csrf_protect(original_password_reset_view)
The view is still protected. Basically, there is no sane way around. (An insane way: write a middleware that sets request.csrf_processing_done = True for that specific URL. Don't do that...)

Can't make class-based RedirectView work

I'm currently trying to migrate my function based views for the new django 1.3 class-based views. To start, I changed a simple RedirectView I had, but I cant get it to work, even worst, I can't understand how the class view works. The mechanism is simple, I have a select field in the index page, the user select an option and clicks "go". The view must get the url corresdponding to that name and redirect there.
When sending the POST signal, django doesn't return anything, just a 405 error in the terminal.
UPDATED code:
index.html
[...]
<div id="widget">
<h2>{% trans "Spaces list" %}</h2><br />
<form method="post" action="/spaces/go/">{% csrf_token %}
<select name="spaces">
{% for space in spaces %}
<option>{{ space.name }}</option>
{% empty %}
<option>{% trans "No spaces" %}</option>
{% endfor %}
</select>
<input type="submit" value="{% trans 'Go' %}" />
</form>
</div>
[...]
views.py
class GoToSpace(RedirectView):
url = "/spaces/"
def get_redirect_url(self, **kwargs):
self.place = get_object_or_404(Space, name = self.request.POST['spaces'])
return self.place.url
urls.py
from django.conf.urls.defaults import *
from e_cidadania.apps.spaces.views import GoToSpace
urlpatterns = patterns('',
(r'^go/', GoToSpace.as_view()),
)
What I am doing wrong?
You can't refer to a class-based view in urls.py just by referencing the name of the class. As is well documented, you need to call the classmethod as_view:
(r'^go/', go_to_space.as_view()),
You should really follow PEP8 and make your class name GoToSpace, which would make the difference from a function more obvious.
Also, get_redirect_url is a method, so it should have self as the first positional argument.
SOLVED:
RedirectView in django 1.3 only accepts GET requests, I was doing a POST (as recommended in django 1.2.x)
This issue was fixed for django 1.3.x (ticket #15739)