How do you translate the slug value of a page? - django

I'm trying to implement a language switcher, for which I'm using the Django recommended form:
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
{% get_current_language as LANGUAGE_CODE %}
<input name="next" type="hidden" value="{{ redirect_to }}">
<input name="language" type="hidden" value="{% if LANGUAGE_CODE == 'en' %}es{% else %}en{% endif %}">
</form>
My urls.py is set up like so:
urlpatterns = [
# Wagtail urls
re_path(r'^cms/', include(wagtailadmin_urls)),
re_path(r'^documents/', include(wagtaildocs_urls)),
# Django urls
path('admin/', admin.site.urls),
path('i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
path(r'', include(wagtail_urls))
)
When I click to change my language, I am correctly forwarded to /en/slug or es/slug, depending on the language I have selected. However the actual slug value is not being translated. Since I have Spanish slugs for the Spanish pages, I am getting a 404 when I switch languages, because I am directed to the English slug value paired with the Spanish locale prefix (es).
I also tried using the slugurl_trans template tag, but that didn't seem to work (maybe because I'm not explicitly defining any URLs in my i18n_patterns call?).
Any guidance on this would be really helpful, as I've spent way too many hours on this!

It has been long but I'm going to post an answer anyway, the best way to get rid of the different slugs problem is by using django signals like this
#receiver(pre_save)
def set_translated_slug_on_new_instance(sender, instance, **kwargs):
if isinstance(instance, Page):
instance.slug_es = instance.slug_en

Related

set_lanuguage is not changing the language of the enitre webpage and miss the redirections by views

My form with language selection buttons and an update button. Customer update form is implemented through django forms and views however language selections are directly implemented in html file using below code:
{% 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{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
1:image of webpage rendered form
Whenever I select any language same page with default english is rendered again.
I have placed the relevant context processors and locale middleware where it should be in settings file.
My root urlConf is given below:
urlpatterns = [
url(r'^', include('custupdate.urls')),
url(r'^i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
url(r'^', include('custupdate.urls')),
My application url conf is given:
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^personBasic', views.person_detail, name='person_detail'),
url(r'^licenseeBasic', views.licensee_detail, name='licensee_detail'),
url(r'^address', views.address, name='address'),
url(r'^contact', views.contact, name='contact'),
url(r'^email', views.email, name='email'),
]
My each url e.g personBasic is hooked to its relevant view and view is hooked with relevant form.
Now when I enter following url in address bar and hit enter
http://mycompany.com/custupdate
Because of above url configurations it goes to index view which redirects to following url
http://mycompany.com/custupdate/personBasic
and image 1 is shown in browser.
So selecting any language renders the same page again without change of language.
When I do inspect element in the browser for any language button when its pressed I get following url requested
http://mycompany.com/custupdate/i18n/setlang/
instead of
http://mycompany.com/custupdate/personBasic/i18n/setlang/
Question is when the language buttons are pressed shouldn't the whole url in address bar be rendered as translated version. Whatever is after custupdate is skipped somehow and i18n/setlang is appended after custupdate where i'm expecting it to be like this
/custupdate/personBasic/i18n/setlang/
or
/custupdate/contact/i18n/setlang/
or
/custupdate/email/i18n/setlang/
Change your root URLconf to this:
urlpatterns = [
url(r'^i18n/', include('django.conf.urls.i18n')),
]
urlpatterns += i18n_patterns(
url(r'^', include('custupdate.urls')),
)
Also, inside your form, remove the hidden input named next, completely. You have not defined a redirect_to variable.
Also, make sure that you have set middlewares in the correct order.

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>

Proper way to handle multiple Django forms in one page with two views?

I've struggled with this problem for the last two days and could use some help. The home page for my Django 1.6 application will include two forms, one that a user can use to sign in to the site and one they can use to sign up (create a login) for the site:
# templates/home/home_page.html
<div class="sign-in-form">
<form action="{% url 'apps.home.views.sign_in' %}" method="post">
{% csrf_token %}
{{ sign_in_form.as_p }}
{% if next %}
<input type="hidden" name="next" value="{{ next }}">
{% else %}
<input type="hidden" name="next" value="{% url 'view-members' %}">
{% endif %}
<input type="submit" value="Sign in">
</form>
</div>
<div class="sign-up-form">
<fieldset>
<legend>Sign up</legend>
<form action="{% url 'apps.home.views.sign_up' %}" method="post">
{% csrf_token %}
{{ sign_up_form.as_p}}
<p><input type="submit" value="Sign up" /></p>
</form>
</fieldset>
</div>
If the user submits, the sign_in form, they'll be taken to a page where they can view other site members. If they submit the sign_up form, they'll be taken to a second signup page where they'll create a user profile, etc.
Originally, I was going to use the technique shown in this question and use one view to handle the homepage. However, I decided to try to use two views because I'm using the Django's actual login view (django.contrib.auth.views.login) so that I can add code to it to detect the user's device (phone, tablet, or computer), and merging that view with my sign_up view would create a very long and complicated view to maintain. I'd prefer to keep the views for both forms separate.
Here's the home page and sign_in views:
# apps/home/views:
def home_page(request, template):
sign_in_form = SignInAuthenticationForm()
sign_up_form = CreateAccountForm()
return render(request, template, {"sign_in_form": sign_in_form,
"sign_up_form": sign_up_form})
#sensitive_post_parameters()
#csrf_protect
#never_cache
def sign_in(request,
template='home_page.html',
redirect_field_name=REDIRECT_FIELD_NAME,
# authentication_form=AuthenticationForm,
authentication_form=SignInAuthenticationForm,
current_app=None, extra_context=None):
# Do device detection here...
# django.contrib.auth.views code goes here...
return response
The signup view will just be your typical, function-based view for processing a form as described in the Django documentation.
What I'm struggling with is my URLconf files. Here's my main and "home" URLconf files:
# conf/urls.py
urlpatterns = patterns('',
url(r'^$', include('apps.home.urls')),
# Other url patterns...
)
# apps/home/urls.py
urlpatterns = patterns('apps.home.views',
url(r'^$',
'home_page',
{'template': 'home/home_page.html'},
name='home-page'),
url(r'^sign_in/$',
'sign_in',
{'template': 'home/home_page.html'},
name='sign-in'),
url(r'^sign_up/$',
'sign_up',
{'template': 'home/home_page.html'},
name='sign-up'),
)
The problem is that I get this error during template rendering:
NoReverseMatch at /
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Request Method: GET
Request URL: http://localhost:8000/
Django Version: 1.6.2
Exception Type: NoReverseMatch
Exception Value:
Reverse for 'apps.home.views.sign_in' with arguments '()' and keyword arguments '{}' not found. 1 pattern(s) tried: ['$sign_in/$']
Exception Location: /Users/smith/venv/swing/lib/python2.7/site-packages/django/core/urlresolvers.py in _reverse_with_prefix, line 429
Python Executable: /Users/smith/venv/swing/bin/python
Python Version: 2.7.5
Python Path:
['/Users/smith/Dropbox/www/swing',
'/Users/smith/venv/swing/lib/python2.7/site-packages/wurfl_cloud-1.0.1-py2.7.egg',
'/Users/smith/venv/swing/lib/python27.zip',
'/Users/smith/venv/swing/lib/python2.7',
'/Users/smith/venv/swing/lib/python2.7/plat-darwin',
'/Users/smith/venv/swing/lib/python2.7/plat-mac',
'/Users/smith/venv/swing/lib/python2.7/plat-mac/lib-scriptpackages',
'/Users/smith/venv/swing/Extras/lib/python',
'/Users/smith/venv/swing/lib/python2.7/lib-tk',
'/Users/smith/venv/swing/lib/python2.7/lib-old',
'/Users/smith/venv/swing/lib/python2.7/lib-dynload',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/Users/smith/venv/swing/lib/python2.7/site-packages']
At first I started to think that maybe it's telling me that it can's find the correct URL pattern in my home/urls.py file because the URL signature in my form is incorrect. Maybe I needed to do this to match the arguments in the sign_in view:
<form action="{% url 'apps.home.views.sign_in' 'home/home_page.html' %}" method="post">
But I'm already showing the template name in the home URLconf. And I don't think I need to pass the other view arguments in the form action (e.g. redirect_field_name) because their optional. In any case, adding this argument to the form action didn't fix it.
One of the things that confuses me is how to set the first url argument. I've set them to r'^sign_in/$' and r'^sign_up/$' because if I set them both to r'^$', the page will render properly but when I submit either form, it justs posts back to the home page. You can see this will happen by doing a "view source" on the page. It shows each form's action will be "/". On the other hand, the way I have it now seems incorrect to me because the site won't actually have a "/sign_in/" and "/sign_up/" URL since both forms are on the home page. Also, is there going to be a problem in which if the user submits one for or the other improperly, errors for both forms will be rendered on the page?
The Django documentation, to the best of my knowledge, doesn't really describe a standard approach for doing what I'm trying to do. It describes how to render multiple versions of the same form. Can anyone tell me what I'm doing wrong?
Thanks.
Your form names are 'sign_in_form' and 'sign_up_form', but in your html you wrote them 'form.as_p' instead of 'sign_in_form.as_p' and 'sign_up_form.as_p' this is the first bug a saw in your code.
The real problem is in your urls configuration. In your main urls.py you have
url(r'^$', include('apps.home.urls')),
Other ...
Though you will not be able to get to localhost:8000/sign_in/ because initially it does not satisfy to ^$ .
Try to change it by
url(r'', include('apps.home.urls')),
and put it to the end of urls.py.
i test this see if this what you want:
view.py
def loginUser(request,**Kargs):
LoginFormSet = formset_factory(LoginForm)
SignFormSet = formset_factory(SignForm)
if request.method == 'POST':
login_formset = LoginFormSet(request.POST, prefix='login')
sign_formset = SignFormSet(request.POST ,prefix='sign')
if login_formset.is_valid():
#do somthing
elif sign_formset.is_valid():
#do somthing
return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})
else:
login_formset = LoginFormSet(prefix='login')
sign_formset = SignFormSet(prefix='sign')
return render(request, 'reservetion/login.html',{'login_formset': login_formset,'sign_formset':sign_formset})
page.html:
<form action="{% url 'loginUser' %}" method="post">
{% csrf_token %}
{{ login_formset.management_form }}
{% for form in login_formset %}
{{ form }}
{% endfor %}
{{ sign_formset.management_form }}
{% for form in sign_formset %}
{{ form }}
{% endfor %}

Namespacing urls in django-registration

I want to keep a clean urls description in my projet, so I use namespaces:
project/urls.py:
urlpatterns = patterns('',
url(r'^contracts/', include('apps.contracts.urls', namespace='contracts')),
url(r'^accounts/', include('apps.registration_custom.backends.vince.urls', namespace='accounts')),
registration_custom/backends/vince/urls.py:
urlpatterns = patterns('',
url(r'^activate/complete/$',
TemplateView.as_view(template_name='registration/activation_complete.html'),
name='registration_activation_complete'),
# Activation keys get matched by \w+ instead of the more specific
# [a-fA-F0-9]{40} because a bad activation key should still get to the view;
# that way it can return a sensible "invalid key" message instead of a
# confusing 404.
url(r'^activate/(?P<activation_key>\w+)/$',
ActivationView.as_view(),
name='registration_activate'),
url(r'^register/$',
CustomRegistrationView.as_view(),
name='registration_register'),
url(r'^register/complete/$',
TemplateView.as_view(template_name='registration/registration_complete.html'),
name='registration_complete'),
url(r'^register/closed/$',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'),
(r'', include('registration.auth_urls')),
)
With this configuration, if I request /accounts/password/reset/ I get an error:
Reverse for 'django.contrib.auth.views.password_reset_done' with arguments '()' and keyword arguments '{}' not found
But if I'm not namespacing my urls, everything goes clean with my /accounts/password/reset/ request.
What I understand is that the django/contrib/auth/views/password_reset view is using reverse() on 'django.contrib.auth.views.password_reset_done'. And the urls dispatcher get lost because it should be asking for 'accounts:auth_password_reset_done'.
Am I guessing right?
Then what would be my options?
EDIT.
The template code that redirect to /accounts/password/reset :
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<form method="post" action="">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="{% trans 'Log in' %}" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
<p>{% trans "Forgot password" %}? {% trans "Reset it" %}!</p>
<p>{% trans "Not member" %}? {% trans "Register" %}!</p>
{% endblock %}
Wahaha, I've made a step in my Django's comprehension!
In fact, Django auth module is looking for a view when he asks for: reverse('django.contrib.auth.views.password_reset_done')
But my urls config is namespaces, so Django is lost (here I don't know exactly, maybe someone can explain better).
So I need to say to Django to look first for a non-namespaced url pattern first, just for it's core code.
So my trick is to add a line in the myproject/urls.py:
urlpatterns = patterns('',
url(r'^contracts/', include('apps.contracts.urls', namespace='contracts')),
# this is tricky
# the default auth module need to reverse some urls like reverse('django.contrib.auth.views.password_reset_done')
# but I want to keep a namespaced urls config
# then I need to supply a first url path to django when he look at non-namespaced urls
url(r'^accounts/', include('registration.auth_urls')),
url(r'^accounts/', include('apps.registration_custom.backends.vince.urls', namespace='accounts')),
And everything is working fine!
I admit that this is not an elegant solution, but it has the benefit to keep my namespaces right, so will be the templates.
Add correct namespace and app name for include('registration.auth_urls') (see last line)
urlpatterns = patterns('',
url(r'^activate/complete/$',
TemplateView.as_view(template_name='registration/activation_complete.html'),
name='registration_activation_complete'),
# Activation keys get matched by \w+ instead of the more specific
# [a-fA-F0-9]{40} because a bad activation key should still get to the view;
# that way it can return a sensible "invalid key" message instead of a
# confusing 404.
url(r'^activate/(?P<activation_key>\w+)/$',
ActivationView.as_view(),
name='registration_activate'),
url(r'^register/$',
CustomRegistrationView.as_view(),
name='registration_register'),
url(r'^register/complete/$',
TemplateView.as_view(template_name='registration/registration_complete.html'),
name='registration_complete'),
url(r'^register/closed/$',
TemplateView.as_view(template_name='registration/registration_closed.html'),
name='registration_disallowed'),
(r'', include('registration.auth_urls'), namespace='accounts', app_name='registration'),
)

django - set_language view giving me a "Page not found" error

Hi there
I've been following the docs on internationalization for django (using mezzanine on django 1.2.5) closely and everything is fine, except when i use a form like the one in the docs to switch language code
like this
<form action="/i18n/setlang/" method="post">
<input name="next" type="hidden" value="/whatever/" />
<select name="language">
{% for lang in LANGUAGES %}
<option value="{{ lang.0 }}">{{ lang.1 }}</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
with my urlconf looking like this
urlpatterns += patterns("",
("^admin/", include(admin.site.urls)),
("^", include("mezzanine.urls")),
(r'^i18n/', include('django.conf.urls.i18n')),
)
when i switch language and hit "go", i get a
Page Not Found (404)
Request Method: POST
Request URL: http://127.0.0.1:8000/i18n/setlang/
No Page matches the given query.
i added the i18n urls and the locale middleware alright.I tried it in a fresh project as well without luck.
Any clues?
Mezzanine's urlpatterns include a "catch all" for pages, so anything underneath it will never be found. To get your patterns working you simply need to swap the last two patterns in your urls.py to look like:
urlpatterns += patterns("",
("^admin/", include(admin.site.urls)),
(r'^i18n/', include('django.conf.urls.i18n')),
("^", include("mezzanine.urls")),
)