This is so simple, yet it seems that its not provided.
Basically, if my site is...
http://www.example.com
http://127.0.0.1:8000
Or a non-root install like
http://www.example.com/ye-ol-django/
http://127.0.0.1:8000/ye-ol-django/
...I would think django would know this and have a constant available in templates.
The solutions I find involve:
Set it up in settings.py with SITE_URL =
Reference settings.py in a view.
Finally access it in the template with {{ SITE_URL }} or something.
Not very D.R.Y.
Not to sound spoiled, but doesn't django provide the {{ GET_ME_THE_ROOT_URL }} reference?
Sorry, django has trained me to expect goodies like this.
Just sayin' if I was writing a framework that would be the first thing I do, besides putting a small fridge beside my desk full of hotpockets and a microwave a safe but close distance away.
Ha! Nice question.
Let's break down your problem. You want some data to be available across all the templates available in your project. And also, you want to provide the value once and not repeat it across views.
Template Context Processors is the thing you are looking for.
In your settings.py file, add a new context_processor to the list of TEMPLATE_CONTEXT_PROCESSORS.
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.media",
"django.core.context_processors.request",
"django.contrib.messages.context_processors.messages",
"your_app.context_processors.root_url"
)
Then, inside your_app, create a file named context_processors.py. This file will contain the following code.
from django.conf import settings
def root_url(request):
"""
Pass your root_url from the settings.py
"""
return {'SITE_URL': settings.ROOT_URL_YOU_WANT_TO_MENTION}
And, in each of your templates, you'll have a {{SITE_URL}} present in the context depending on the value you provide to ROOT_URL_YOU_WANT_TO_MENTION in your settings.py file.
Django sure spoils everyone. But provides the mechanisms to keep you spoilt.
Hope this solves your problem.
If you're rendering the template from a request, you can just name your root view, then refer to it with the url tag:
In your root urls.py:
url(r'^$', HomePageView.as_view(), name='home'),
In template.html:
click here
More good info over in the django docs: https://docs.djangoproject.com/en/1.8/ref/templates/builtins/#url
Related
I am currently working on implementing Duo Two-Factor Authentication into my django project. Currently it looks like django-duo-auth is the best package for this. I installed the package and went through the basic instructions on their README:
https://github.com/Elemnir/django-duo-auth/blob/master/README.rst
However this has caused my project to continuously redirect to a nonexistent subdirectory of 'duo' which is what I named the path. For example my app is loaded in XX.XX.XX.XX:YYYY Going to that url auto redirects the page to:
http://XX.XX.XX.XX:YYYY/duo/login/?next=/
Or, XX.XX.XX.XX:YYYY/admin auto redirects to:
http://XX.XX.XX.XX:YYYY/duo/login/?next=/admin
This simply will lead to django's generic base.html that duo_auth_form.html extends
Here are some snippets of relevant code, though it doesn't differ to much from the package's README suggestions
/urls.py
urlpatterns = [
...
path('admin/', admin.site.urls),
path('duo/', include('duo_auth.urls')),
]
/settings.py
INSTALLED_APPS = [
...
'duo_auth',
]
MIDDLEWARE = [
...
'duo_auth.middleware.DuoAuthMiddleware',
]
DUO_CONFIG = {
'DEFAULT': {
'HOST': '<api-host-url>',
'IKEY': '<integration_key>',
'AKEY': '<app_secret_key>',
'SKEY': '<secret_key>',
'FIRST_STAGE_BACKENDS': [
'django.contrib.auth.backends.ModelBackend',
]
}
}
The only difference anywhere from the read me is a slight redirection in the sample do_auth_form.html
where I extend to a subdirectory of my templates i.e. {% extends "dir\base.html" %} at the top of the file.
It appears like this package is fairly new and there isn't a lot of forums for issues so I figured it would be best to ask here. Any help would be appreciated!
I believe this is actually the django-duo-auth package working as intended. The way the middleware works is that after adding it to your project, any authenticated user who was authenticated using one of the FIRST_STAGE_BACKENDS will be checked to see if they've been authenticated with Duo as well, if not, they'll be redirected to the Duo login page at duo/login/ and prompted to complete a Duo authentication, similar to how Django's built-in #login_required decorator redirects an anonymous user to accounts/login/ to log in.
If you have users you don't want to force a second factor for, I would recommend creating a subclass of the ModelBackend that only authenticates for those users. Similar to the approach described in this issue, but inverting the logic:
https://github.com/Elemnir/django-duo-auth/issues/1
Here is a quote from Two Scoops of Django: Best Practices For Django 1.6:
In the past, we placed all API view code into a dedicated Django app
called api or apiv1, with custom logic in some of the REST views,
serializers, and more. In theory it’s a pretty good approach, but in
practice it means we have logic for a particular app in more than just
one location.
Our current approach is to lean on URL configuration. When building a
project-wide API we write the REST views in the views.py modules, wire
them into a URLConf called something like core/api.py or
core/apiv1.py and include that from the project root's urls.py
module. This means that we might have something like the following
code:
# core/api.py
""" Called from the project root's urls.py URLConf thus:
url(r" ˆ api/", include("core.api"), namespace="api"),
"""
from django.conf.urls.defaults import patterns, url
from flavors import views as flavor_views
from users import views as user_views
urlpatterns = patterns("",
# {% url "api:flavors" %}
url(
regex=r" ˆ flavors/ $ ",
view=flavor_views.FlavorCreateReadView.as_view(),
name="flavors"
),
# {% url "api:flavors" flavor.slug %}
url(
regex=r" ˆ flavors/(?P<slug>[-\w]+)/ $ ",
view=flavor_views.FlavorReadUpdateDeleteView.as_view(),
name="flavors"
),
# {% url "api:users" %}
url(
regex=r" ˆ users/ $ ",
view=user_views.UserCreateReadView.as_view(),
name="users"
),
# {% url "api:users" user.slug %}
url(
regex=r" ˆ users/(?P<slug>[-\w]+)/ $ ",
view=user_views.UserReadUpdateDeleteView.as_view(),
name="users"
),
)
But I don't understand where to put core/api.py. Is this a separate Django app called core? Where api.py should sit?
It means create the file you have as core/api.py (along with an empty core/__init__.py file) and then add the line url(r" ˆ api/", include("core.api"), namespace="api") to the root urls.py file of your project.
You don't have to call it core/api.py, that is just a suggestion from the authors
what does we write the REST views in the views.py modules mean?
It means what you've done, for each of the Django apps in your project, such as flavors, users they will have a views.py (or views/*.py) in them where you'd put the code for both the API and non-API views. (this is just a sane naming convention, nothing more... Django relies on the urlpatterns to tell it how to connect url routes to view code)
It's great to build up stuff like this from scratch as a way to learn Django. If you're doing a serious REST API project have a look at Django REST framework.
I want to use django's password change/reset views so for example for the view
django.contrib.auth.views.password_change
I need create a template named
registration/password_change_form.html
the problem is that even though I have this template implemented in my project, django still shows the password-change page of the admin website, the only way I can make django use my template is by renaming it to something different - like registration/password_change_form_1.html and then pass the name
url(r'^password/change/$',
auth_views.password_change,
{'template_name': 'registration/password_change_form_1.html',
'password_change_form': MyPasswordChangeForm},
name='password_change'),
Am I missing something here? why won't django use my template when I use the default name?
I think because your app is under django.contribute.admin in the INSTALLED_APP.
Django automatically generates the admin template with the default name, so, if you use the admin, you must specify a different template name.
It simply fails to find your template, since it is overiden by the generated one.
Add in settings
INSTALLED_APPS = (
...
'registration',
)
After
TEMPLATE_DIRS = (
...
"/home/user/templates",
)
Add in directory templates "registration"
base.html that will contain the template and other templates
run in django==1.5
I’m writing a simple multilanguage website in Django and I struggle a bit with switching languages. I thought it would be good to have different urls for each language (e.g. /en/contact/ for the english site, /de/kontakt/ for the german site). Maybe this does not only look better but does also make sense in the SEO context.
So I have in urls.py:
urlpatterns = pattern(‘’,
url(r’^de/kontakt/$’, mysite.views.DeKontaktView, name=‘kontakt’,),
url(r’^en/contact/$’, mysite.views.EnContactView, name=‘contact’,),
)
Now I’d like to have links on every page (in the base template) to switch the language between german and english. In the Django documentation I found the ‘set_language redirect view’ (https://docs.djangoproject.com/en/1.6/topics/i18n/translation/#the-set-language-redirect-view).
My problem is where and how to tell the view where it should redirect when switching languages. I do not always want to redirect to the frontpage of my site but to the corresponding page in the other language - which has a completely different url - not only a different language prefix in the url.
Since the ‘set_language redirect view’ seems to use the referrer unless there is a next parameter in the post data, my first idea was something like this:
views.py:
def EnContactView(request):
…
if request.LANGUAGE_CODE == ‘en’:
return render_to_response(‘en/contact.html’), context)
else:
return redirect(‘/de/kontakt/‘)
def DeKontaktView(request):
…
if request.LANGUAGE_CODE == ‘de’:
return render_to_response(‘de/kontakt.html’), context)
else:
return redirect(‘/en/contact/‘)
But I think this may not be a good solution since this would also redirect depending on the browser language. For example: if someone with browser language ‘en’ visits one of our german urls directly, e.g. via Google. Since there is neither a cookie ‘en’ nor a language choice in the session, the visitor would be redirected to the english url - which is not intended.
So what are the best practices for these situations? To sum up: I have completely different urls for the languages - not only a different language prefix in the url. For every language I do have one template (directories templates/en/ and templates/de/).
How can I switch between the corresponding pages in different languages?
and by the way: Is it possible to not use a form as a language switcher but simple links ‘de’ and ‘en’?
It would be great if someone could help me out. The “language thing” is quite confusing for a django noob.
https://docs.djangoproject.com/en/1.6/topics/i18n/translation/#translating-url-patterns
#setting.py
gettext = lambda s: s
LANGUAGES = (
('en', gettext('English')),
('de', gettext('De')),
)
#url
from django.http import Http404
from django.conf.urls.i18n import i18n_patterns
urlpatterns += i18n_patterns('',
url(r'^contact/$', mysite.views.ContactView, name='contact'),
)
#view
def ContactView(request)
if request.LANGUAGE_CODE == 'de':
return render_to_response('de/kontakt.html')
if request.LANGUAGE_CODE == 'en':
return render_to_response('en/contact.html')
raise Http404
django.conf.urls.i18n.i18n_patterns will take care of the language prefix part, django.views.i18n.set_language of (most of) the language switching part, and you can use django.utils.translation.ugettext_lazy to translate your url patterns just like any other translatable "static" text. You'll still have to handle content's translation one way or another (there are quite a few more or less pluggable apps solving this for Django models), but this part really depends on your application's domain and logic.
Here is a more full blown solution for those having problems with translations or are creating a multi-language site.
In settings.py …
Add to MIDDLEWEAR_CLASSES, locale, it enables language selection based on request:
'django.middleware.locale.LocaleMiddleware',
Add LOCALE_PATHS, this is where your translation files will be stored, also enable i18N:
USE_I18N = True
LOCALE_PATHS = (
os.path.join(PROJECT_PATH, 'locale/'),
)
Set LANGUAGES that you will be translating the site to:
ugettext = lambda s: s
LANGUAGES = (
('en', ugettext('English')),
('fr', ugettext('French')),
('pl', ugettext('Polish')),
)
Add i18n template context processor, requests will now include LANGUAGES and LANGUAGE_CODE:
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n', # this one
'django.core.context_processors.request',
'django.core.context_processors.static',
'django.contrib.messages.context_processors.messages',
)
Nest, in urls.py :
In url_patterns, add the below, it will enable the set language redirect view:
url(r'^i18n/', include('django.conf.urls.i18n')),
See Miscellaneous in Translations for more on this.
Add the following imports, and encapsulate the urls you want translated with i18n_patterns. Here is what mine looks like:
from django.conf.urls.i18n import i18n_patterns
from django.utils.translation import ugettext_lazy as _
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^i18n/', include('django.conf.urls.i18n')),
)
urlpatterns += i18n_patterns('',
(_(r'^dual-lang/'), include('duallang.urls')),
(r'^', include('home.urls')),
)
Note: You can also drop your admin urls into the i18n_patterns.
Now anywhere you use text and want to convert it, import lazytext and wrap every string with it like so _('text'), you can even go to your other urls.py files and do url translation like so:
url(_(r'^dual_language/$'), landing, name='duallang_landing'),
You can wrap text that you want translated in your other files, such as models.py, views.py etc.. Here is an example model field with translations for label and help_text:
name = models.CharField(_('name'), max_length=255, unique=True, help_text=_("Name of the FAQ Topic"))
In your html templates...
Now you can go into your templates and load the i18n templatetag and use trans and transblock on the static stuff you want to translate. Here is an example:
{% load i18n %}
{% trans "This is a translation" %}<br><br>
{% blocktrans with book_t='book title'|title author_t='an author'|title %}
This is {{ book_t }} by {{ author_t }}. Block trans is powerful!
{% endblocktrans %}
Now run a makemessages for each of your locales:
./manage.py makemessages -l pl
And now all is left is to go into your /locales folder, and edit each of the .po files. Fill in the data for each msgstr. Here is one such example of that:
msgid "English"
msgstr "Angielski"
Leave the ones that make sense blank to pick up the default language.
And finally compile the messages:
./manage.py compilemessages
There is a lot more to learn with translations and internationalization is closely related to this topic, so check out the docs for it too. I also recommend checking out some of the internationalization packages available for Django like django-rosetta, and django-linguo. They help translate model content, django-rosetta does not create new entries for this in your database, while django-linguo does.
If you followed this you should be off to a good start. I believe this is the most standardized way to get your site running in multiple languages. Cheers!
For example I can point the url '^/accounts/password/reset/$' to django.contrib.auth.views.password_reset with my template filename in the context but I think need to send more context details.
I need to know exactly what context to add for each of the password reset and change views.
If you take a look at the sources for django.contrib.auth.views.password_reset you'll see that it uses RequestContext. The upshot is, you can use Context Processors to modify the context which may allow you to inject the information that you need.
The b-list has a good introduction to context processors.
Edit (I seem to have been confused about what the actual question was):
You'll notice that password_reset takes a named parameter called template_name:
def password_reset(request, is_admin_site=False,
template_name='registration/password_reset_form.html',
email_template_name='registration/password_reset_email.html',
password_reset_form=PasswordResetForm,
token_generator=default_token_generator,
post_reset_redirect=None):
Check password_reset for more information.
... thus, with a urls.py like:
from django.conf.urls.defaults import *
from django.contrib.auth.views import password_reset
urlpatterns = patterns('',
(r'^/accounts/password/reset/$', password_reset, {'template_name': 'my_templates/password_reset.html'}),
...
)
django.contrib.auth.views.password_reset will be called for URLs matching '/accounts/password/reset' with the keyword argument template_name = 'my_templates/password_reset.html'.
Otherwise, you don't need to provide any context as the password_reset view takes care of itself. If you want to see what context you have available, you can trigger a TemplateSyntax error and look through the stack trace find the frame with a local variable named context. If you want to modify the context then what I said above about context processors is probably the way to go.
In summary: what do you need to do to use your own template? Provide a template_name keyword argument to the view when it is called. You can supply keyword arguments to views by including a dictionary as the third member of a URL pattern tuple.
Strongly recommend this article.
I just plugged it in and it worked
http://garmoncheg.blogspot.com.au/2012/07/django-resetting-passwords-with.html
You just need to wrap the existing functions and pass in the template you want. For example:
from django.contrib.auth.views import password_reset
def my_password_reset(request, template_name='path/to/my/template'):
return password_reset(request, template_name)
To see this just have a look at the function declartion of the built in views:
http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/views.py#L74
You can do the following:
add to your urlpatterns (r'^/accounts/password/reset/$', password_reset)
put your template in '/templates/registration/password_reset_form.html'
make your app come before 'django.contrib.auth' in INSTALLED_APPS
Explanation:
When the templates are loaded, they are searched in your INSTALLED_APPS variable in settings.py .
The order is dictated by the definition's rank in INSTALLED_APPS, so since your app come before 'django.contrib.auth' your template were loaded (reference: https://docs.djangoproject.com/en/dev/ref/templates/api/#django.template.loaders.app_directories.Loader).
Motivation of approach:
I want be more dry and don't repeat for any view(defined by django) the template name (they are already defined in django)
I want a smallest url.py
Another, perhaps simpler, solution is to add your override template directory to the DIRS entry of the TEMPLATES setting in settings.py. (I think this setting is new in Django 1.8. It may have been called TEMPLATE_DIRS in previous Django versions.)
Like so:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
# allow overriding templates from other installed apps
'DIRS': ['my_app/templates'],
'APP_DIRS': True,
}]
Then put your override template files under my_app/templates. So the overridden password reset template would be my_app/templates/registration/password_reset_form.html
The documentation says that there only one context variable, form.
If you're having trouble with login (which is common), the documentation says there are three context variables:
form: A Form object representing the login form. See the forms documentation for more on Form objects.
next: The URL to redirect to after successful login. This may contain a query string, too.
site_name: The name of the current Site, according to the SITE_ID setting.
I was using this two lines in the url and the template from the admin what i was changing to my need
url(r'^change-password/$', 'django.contrib.auth.views.password_change', {
'template_name': 'password_change_form.html'}, name="password-change"),
url(r'^change-password-done/$', 'django.contrib.auth.views.password_change_done', {
'template_name': 'password_change_done.html'
}, name="password-change-done")