I want to let user change language of a site by click on a country flag.
In my models.py file i have:
class RegularUser(models.Model):
(...)
language = models.CharField(max_length = 10, null=True, blank=True, choices=[(a, _(b)) for (a,b) in settings.LANGUAGES], verbose_name=_("Language"))
I also made there a function:
def set_language(self, new_lang):
lllang = self.language
lllang = new_lang
In my html file i have:
function setLang(lang){
language = document.getElementById("language")
lang_form = document.getElementById("language_form")
language.value= lang
lang_form.submit()
{{request.user.get_profile.set_language(lang) }}
}
This function in setted to some button as "onclick".
This should do two thing:
1. Change immediately the language (it's done)
2. Change uset language in the database, so next time when we will log in - it will be as we set it now (it doesn't work :( )
I'm getting an error such:
TemplateSyntaxError at /
Could not parse the remainder: '("lang")' from 'request.user.get_profile.set_language("lang")'
Just to tell - if I'll put :
{{request.user.get_profile.get_language}}
Then I'm getting code of my language, so it's fine.
get_language function from models.py:
def get_language(self):
if self.language:
return self.language
elif self.location and self.location.country:
return self.location.country.iso.lower()[:2]
else:
return None
Umm ... any help?
Am I just giving the "lang" in a wrong way, or I don't get something in Django?
In a Django template, you cannot call a Python function with parameters. See https://docs.djangoproject.com/en/1.4/topics/templates/#variables . That's why you get no error message when you write {{request.user.get_profile.get_language}} (actually, your function is called without parameters, and the resulting exception is swallowed by Django).
Also, you cannot use the lang parameter, which is a client-side JavaScript function parameter, in a Python function on the server side. Try calling the function using AJAX - you'll need to add another view function for this, and I strongly suggest you don't use bare JavaScript, but a library like jQuery.
For your actual problem (letting the user set his preferred language), there's already a function for that in Django's internationalization package.
Related
I have a site with that offers 2 language choices - English & Japanese.
To change between the languages, A user clicks a button taking them to a view which changes the setting. Previously, it had always redirected to the home page but now I want to take them to where they were before.
The current path is passed as a url param which is then saved to a response variable, which then has it's language cookie set before being returned.
For some reason, when I use the parameter in the redirect function, the language cookie doesn't set at all but using reverse (i.e. when it was hard coded to go back home) wass working fine.
How do I get the redirect function with the param to work like the one set with reverse?
Thanks in advance!
Code:
Template Links:
English
日本語
Urls:
path('lang/<str:language>/', v.change_language, name='language')
View:
def change_language(request, language): # language is 'en' or 'ja'
redirect_page = request.GET.get('q') # e.g. '/about/'
# note: redirect_page == reverse('about') is True
# make sure language is available
valid = False
for l in settings.LANGUAGES:
if l[0] == language:
valid = True
if not valid:
raise Http404(_('選択した言語は利用できません'))
# Make language the setting for the session
translation.activate(language)
response = redirect(redirect_page) # Changing this to use reverse works
response.set_cookie(settings.LANGUAGE_COOKIE_NAME, language)
return response
I found a workaround to the above problem.
Fixed by adding the {{ request.resolver_match.url_name }} to the a tag's query param and then called reverse on that query param within the view:
Link:
English
to:
English
The view is then refactored:
response = redirect(redirect_page)
To:
response = redirect(reverse(redirect_url_name))
Tl; dr: Is there a way to override the default behaviour of reverse?
In my django project I have alot of urls such as
url(r'^\w+/company/', include("company.urls", namespace="company")),
Which allows for urls such as
.../companyA/company/
.../companyB/company/
So that I can then use a custom middleware to modify the request to include some specific details based upon what company is using my site
This all works fine except for when django is trying to decipher the full path with reverse and {% url .. %}...
It seems to be returning /x/company/ as a default match for the regex. since the django.utils.regex_helper method next_char has an escape mapping for \w to map to x
The url tag I have been able to override to replace the /x/ with the correct company name and I am wondering if there is a similar thing I can do to override reverse in the same way, or anything else that I can do to resolve this problem?
Previously, I was using
url(r'^(?P<company_name>\w+)/company/', include("company.urls", namespace="company"))
But this meant I had to include a parameter in every view
def view(request, company_name):
...
As well as include it in all my other calls to the view (i.e with the {% url %}) which I am trying to avoid.
For ease of use, Django packages as compiled a page full of every possible existing django package that can accomplish this. However below is my own simple implementation
I modified my nginx proxy config to use the following
server_name ~(?<short_url>\w+)\.domainurl\.com$;
... stuff related to static files here
location / {
proxy_set_header X-CustomUrl $short_url;
.... other proxy settings
}
What this does is create a variable inside a request header that can then be used within Django. This variable I then used within a custom middleware to extend a request with a reference to the model which allows its use anywhere.
class CompanyMiddleware(object):
def process_request(self, request):
if settings.DEBUG:
request.company = CompanyClass.objects.get(id=1)
return None
short_url = request.META.get("HTTP_X_CUSTOMURL")
try:
company = CompanyClass.objects.get(short_url=short_url)
except Model.DoesNotExist:
return HttpResponseBadRequest('Company not found')
request.company = company
return None
Examples:
www.companya.domainurl.com # short_url is companya
test.domainurl.com # short_url is test
To use this within a template, context processors must be added to the settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
'django.core.context_processors.request' # This one in particular
)
I know that webapp2_cached_property replaces a method with data after the first call for each call to it thereafter, and thus my problems arise.
I have a multilingual site and I am using a form to build some simple select menus. The select menus are data that change language. Obviously if a user changes the language on the system I would like to rebuild the form. However, I don't want to remove the webapp2_cached_property as it will then rebuild the form every time the user calls the same url and that will slow down the system. So does anyone know a way to force webapp2_cached_property to re-evaluate on demand, e.g. when client changes language. At the moment I have everything else in the selected language but the select data in the default language. Anything down and dirty will do! Ah, yes this only happens on production and not on the dev server...
class HomeRequestHandler(BaseHandler):
"""
Handler to show the home page
"""
def get(self):
params = {}
params['products'] = []
params['max_searches'] = 1
params['user_search_count'] = 0
return self.render_template('index.html', **params)
#webapp2.cached_property
def form(self):
import product.product_data.forms as forms
return forms.ProductForm(self)
Ok, I have tried the following but still the language is not changing in production...
Added this to my base handler - it's working!
if hasattr(self, 'form'):
if self.locale != self.oldLocale and hasattr(self, 'form_no_cache'):
new_form = self.form_no_cache
kwargs['form'] = new_form()
logging.info('reset form')
logging.info(kwargs['form'].product_type())
else:
kwargs['form'] = self.form
logging.info('using cached form')
And added this to my home handler
def form_no_cache(self):
import product.product_data.forms as forms
return forms.ProductForm(self)
All this is fine in development and the logs seem correct in development and production...
Any ideas people?
ok, couldn't figure this one out, so rewrote the code to build selects in a simple def and pass as a parameter instead of form. Seems to be working. I have my suspicions regarding wtforms though, but it's a pain not knowing, but no time...
Django newbie here, need help on basic middleware to redirect to another view if a certain model field is empty.
I am creating a terms of agreement page that users must get redirected to right after they signup to the platform if their filed_terms field on their Profile model is empty.
I am using middleware for this. However I am unable to get this to work. This is my middleware class:
class TermsMiddleware(object):
def process_request(self, request):
if request.user.profile.filled_terms is None:
return redirect(reverse(terms))
This gives me the following error:
global name 'terms' is not defined
I also have the url matcher that works perfectly when I navigate to it manually:
url(r'^terms/', 'my_app.views.terms')
I have a terms.html template and a terms view in my views.py file that is working perfectly in all other respects. I have also added it to the settings middleware requirements to make sure it loads.
Do I have to import something from views or url dispatcher into my middleware file? If so what would that be? I have been at this for a while an cannot find anything helpful.
reverse function takes url name instead on the regex. So you need to add name on your url configuration. Here is the example.
url(r'^terms/', 'my_app.views.terms', name='terms')
Add this in your views.py
from django.core.urlresolvers import reverse
And you need to fix your reverse function into.
return redirect(reverse('terms'))
Python interpret your terms as a variable and you have no variable named terms while you need to put string on reverse.
in mako template, i use this
${request.environ['repoze.who.identity']['user']}
and the render in controller:
render('file.html')
can i write this better without passing in parameter everytime?
Well, you can auto add the varible in the base controller in /lib/base.py. This will add it to every controller in your pylons application automatically. I'm using repoze.what and what I do is in base.py I put:
# if there's no user set, just setup a blank instance
c.current_user = auth.get_user(User())
And that's just a convienence function I wrote into an auth lib. User() is a blank instance of the User model so that the template has something and won't throw a invalid key error.
def get_user(default):
"""Return the user object from the `repoze.who` Metadata Plugin
:param default: default item to send back if user not logged in
Since we might not be logged in and template choke on trying to output
None/empty data we can pass in a blank User object to get back as a default
and the templates should work ok with default empty values on that
"""
if 'repoze.who.identity' in request.environ:
return request.environ['repoze.who.identity']['user']
else:
return default