How can I access environment variables directly in a Django template? - django

I'm looking to do something like this non-working code in my Django template:
{% if os.environ.DJANGO_SETTINGS_MODULE == "settings.staging" %}
Is something like this possible? My workaround is creating a context processor to make the variable available across all templates, but wanted to know if there is a more direct way to achieve the same result.

Use context_processor, do as below and you should be able to access os.environ['DJANGO_SETTINGS_MODULE'] as SETTING_TYPE in templates. Example you can use {% if SETTING_TYPE == "settings.staging" %}
project/context_processors.py
import os
def export_vars(request):
data = {}
data['SETTING_TYPE'] = os.environ['DJANGO_SETTINGS_MODULE']
return data
project/settings.py (your actual settings file)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'project.context_processors.export_vars',
...
]
}
}
]

Extending on #vinay kumar's comment, you can create a custom template filter in the following way:
application/template_tags_folder/template_tags_file.py
from django.template.defaulttags import register
import os
#register.filter
def env(key):
return os.environ.get(key, None)
And then in your template you can access it this way:
template.html
{% if 'DJANGO_SETTINGS_MODULE'|env == 'app_name.staging_settings' %}
Finally I leave a django docs reference and a stackoverflow reference for creating custom template tags and filters in django.

Related

dynamiclly change pages with slug and include tag in template

I was trying to build a template preview in my website, which is when user click the specific template preview on the templates list page, it will direct to the template detail page, the urls.py code is like below:
urls.py:
urlpatterns = [
path('choose_templates/<slug:slug>/', views.template_preview, name='template_preview'),
]
views.py:
def template_preview(request,slug):
context = {
'slug':slug
}
return render(request,'./html/htmlbase.html',context)
htmlbase.html:
{% include slug %}
<!DOCTYPE html>
<html>
<head></head>
<body>
</body>
</html>
what I want to do is when user clicks on the different template preview buttons, it will direct to the corresponding template detail page. the code above result in " TemplateDoesNotExist".
Could anyone help me with this?
Thank you!
Before moving on, your problem sounds like you didn't configure your templates directory correctly. Conventionally, you want to add this to your settings.py (although there should be an empty list there):
# settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates'),], # this line!
'APP_DIRS': True,
'OPTIONS': {
# ... some options here ...
},
},
]
and then if you put any of your templates inside a folder named templates, Django will automatically look for it.
More information on here

Switch language in jinja template

I'm migrating a multi lingual Django application from Django's template engine to Jinja2. In the templates I currently switch the active language on a per object basis using Django's language template tag i.e.:
{% load i18n %}
<h1>{% trans 'Page title' %}</h1>
<ul>
{% for obj in object_list %}
{% language obj.language_code %}
<li>{% trans 'view' %}: {{ obj.title }}
{% endlanguage %}
{% endfor %}
</ul>
We also use i18n_patterns so the urls of each object are language specific as well.
I'm stuck on how to convert this to Jinja. I cannot use Django's i18n template tags and cannot find something equivalent for Jinja.
I was also looking at Babel to help with extracting messages from the templates. So a solution that works with Babel as well as with Django would be preferred.
It turns out it's fairly simple to do this by writing a custom jinja2 extension (I've based this on the example in the jinja2 docs):
from django.utils import translation
from jinja2.ext import Extension, nodes
class LanguageExtension(Extension):
tags = {'language'}
def parse(self, parser):
lineno = next(parser.stream).lineno
# Parse the language code argument
args = [parser.parse_expression()]
# Parse everything between the start and end tag:
body = parser.parse_statements(['name:endlanguage'], drop_needle=True)
# Call the _switch_language method with the given language code and body
return nodes.CallBlock(self.call_method('_switch_language', args), [], [], body).set_lineno(lineno)
def _switch_language(self, language_code, caller):
with translation.override(language_code):
# Temporarily override the active language and render the body
output = caller()
return output
# Add jinja2's i18n extension
env.add_extension('jinja2.ext.i18n')
# Install Django's translation module as the gettext provider
env.install_gettext_translations(translation, newstyle=True)
# Add the language extension to the jinja2 environment
environment.add_extension(LanguageExtension)
With this extension in place switching the active translation language is pretty much exactly like how you'd do it in Django:
{% language 'en' %}{{ _('Hello World'){% endlanguage %}
The only caveat is that when using Django as a gettext provider and Babel as a message extractor it's important to tell Babel to set the message domain to django when running init/update/compile_catalog.
I have this code snippet to switch between languages in jinja2.
def change_lang(request, lang=None, *args, **kwargs):
"""
Get active page's url by a specified language, it activates
Usage: {{ change_lang(request, 'en') }}
"""
path = request.path
url_parts = resolve(path)
url = path
cur_language = get_language()
try:
activate(lang)
url = reverse(url_parts.view_name, kwargs=url_parts.kwargs)
finally:
activate(cur_language)
return "%s" % url
in settings.py
TEMPLATES = [
{
"BACKEND": "django_jinja.backend.Jinja2",
'DIRS': [
os.path.join(BASE_DIR, 'templates/jinja'),
],
"OPTIONS": {
# Match the template names ending in .html but not the ones in the admin folder.
"match_extension": ".html",
"match_regex": r"^(?!admin/).*",
"newstyle_gettext": True,
"extensions": [
"jinja2.ext.do",
"jinja2.ext.loopcontrols",
"jinja2.ext.with_",
"jinja2.ext.i18n",
"jinja2.ext.autoescape",
"django_jinja.builtins.extensions.CsrfExtension",
"django_jinja.builtins.extensions.CacheExtension",
"django_jinja.builtins.extensions.TimezoneExtension",
"django_jinja.builtins.extensions.UrlsExtension",
"django_jinja.builtins.extensions.StaticFilesExtension",
"django_jinja.builtins.extensions.DjangoFiltersExtension",
],
'globals': {
'change_lang': 'drug.utils.change_lang'
},
"bytecode_cache": {
"name": "default",
"backend": "django_jinja.cache.BytecodeCache",
"enabled": False,
},
"autoescape": True,
"auto_reload": DEBUG,
"translation_engine": "django.utils.translation",
"context_processors": [
"dashboard.context_processors.auth",
# "django.template.context_processors.debug",
"django.template.context_processors.i18n",
# "django.template.context_processors.media",
# "django.template.context_processors.static",
# "django.template.context_processors.tz",
"django.contrib.messages.context_processors.messages",
]
}
},
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
os.path.join(BASE_DIR, 'templates'),
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
]
},
},]
and then you can use this in anywhere in your templates {{ _('Hello World') }}

Django - use custom template loader on a per-request basis?

Is there a lower-level way to provide the list of loaders when rendering a template, as opposed to always having Django use the setting?
I'd like to use a custom template loader instance for only a few views (I have my reasons).
It looks like you'll have to write some code of your own to do it. Let's take a look at the normal code path for loading templates, if you use, say, render_to_response, where the relevant part of the source is:
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
That's a call to django.template.loader.render_to_string, which passes through some other functions and eventually ends up calling find_template.
The first time find_template is called, in initializes the global template_source_loaders cache based on settings.TEMPLATE_LOADERS. So it looks like there's no just extra argument you can pass in or anything like that.
One possibility might be to add some loaders to django.template.loader.template_source_loaders just for the duration of that view. I don't know if that will cause other problems; it feels dirty, but if it works, it'll be pretty easy. (Just make a view decorator that does it.)
If you don't want to do that, it looks like you'll have to replicate the work of render_to_string with your own code (if you're really sure you want to use per-view template loaders, which I'm accepting as a premise for the sake of this question but I bet isn't actually necessary). There's not all that much code there, and if you know in advance a specific loader and a single template name that you want to use, it's actually pretty easy. (This is untested but will probably pretty much work.)
def render_to_response_with_loader(loader, name,
dictionary=None, context_instance=None, mimetype=None, dirs=None):
# from find_template
t, display_name = loader(name, dirs)
# from get_template
if not hasattr(t, 'render'):
# template needs to be compiled
t = django.template.loader.get_template_from_string(t, origin, template_name)
# from render_to_string
if not context_instance:
rendered = t.render(Context(dictionary))
else:
# Add the dictionary to the context stack, ensuring it gets removed again
# to keep the context_instance in the same state it started in.
context_instance.update(dictionary)
try:
rendered = t.render(context_instance)
finally:
context_instance.pop()
# from render_to_response
return HttpResponse(rendered, mimetype=mimetype)
If you want to support multiple possible loaders or a list of possible filenames, just copy the relevant code from django.template.loader.
I ended up doing this by modifying template_source_loaders as Dougal suggested. Like he said, I'm not sure this is safe (could it create a race condition?), but it works for my particular case at the moment. The benefit of doing it this way over the other way Dougal suggested is that it makes sure that {% extends %} and {% include %} also use the modified loaders. Here's my render_to_string with custom loaders:
def render_to_string_with_loader(*args, **kwargs):
""" Call render_to_string using ReportTemplateLoader to find templates. """
import django.template.loader as loader
old_loaders = settings.TEMPLATE_LOADERS
settings.TEMPLATE_LOADERS = ('main.loaders.ReportTemplateLoader',)
loader.template_source_loaders = None # force refresh from settings
try:
out = render_to_string(*args, **kwargs)
finally:
# use finally make sure template errors can't mess up later requests
settings.TEMPLATE_LOADERS = old_loaders
loader.template_source_loaders = None
This is an old question but as of 2021 (Django 3.2), here's what I did.
What I needed:
Serve different templates depending on the request (in my case the domain used)
Use only one instance of Django (= 1 IP/port)
(some multi-domain solutions were about creating a new instance with different DIRS)
For the multi-site / multi-domain:
Add 'django.contrib.sites' in INSTALLED_APPS in settings.py
This enables the Django sites framework
Add the 'django.contrib.sites.middleware.CurrentSiteMiddleware' to MIDDLEWARES in your settings.py
This adds a site property for every request handled by Django
For using per-request templates
Create extra engines
In TEMPLATES in settings.py
For example, I use Django engine. I created the same engine again with added DIRS where it could get templates.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
},
{
'NAME': 'a.local',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates/a.local'),
os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
},
{
'NAME': 'b.local',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates/b.local'),
os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
}
]
Use the using kwarg in render()
Set the rendering engine to use in render()
Before:
render(request, 'template.html', context=context_data)
After: render(request, 'template.html', context=context_data, using=request.site.domain)
(in my case, request.site.domain is either a.local or b.local, which is precisely the name of an engine I just created)
Override render (optional, hacky)
Avoid changing all your render everywhere.
This is nasty, you shouldn't do that. Move to classed-based views. Here it is.
def render(request, *args, **kwargs):
return shortcut_render(request, *args, **kwargs, using=request.site.domain)

Django: How to get language code in template?

Is there's some global variable for gettin' language code in django template or atleast passing it through view?
something like: {{ LANG }} should produce "en" for example..
I really not comfortable when people using request.LANGUAGE_CODE.
Detailed explanation would be appreciated =)
It's an old topic. But some might find it useful.
{% load i18n %}
...
{% get_current_language as LANGUAGE_CODE %}
Django reference and example.
If it didn't already exist, you would need to write a template context processor. Here's how you'd do that.
Put this somewhere:
def lang_context_processor(request):
return {'LANG': request.LANGUAGE_CODE}
And then, add a reference to it the TEMPLATE_CONTEXT_PROCESSORS setting. Something like this:
from django.conf import global_settings
TEMPLATE_CONTEXT_PROCESSORS = global_settings.TEMPLATE_CONTEXT_PROCESSORS + (
'myproject.myapp.templatecontext.lang_context_processor',
)
(I recommend adding to the global setting because it means you don't break things accidentally when a new context processor is added to the defaults.)
However, it does exist, as the inbuilt template context processor django.template.context_processors.i18n. You can access it as LANGUAGE_CODE.
Purely for interest, here's the definition of that function:
def i18n(request):
from django.utils import translation
return {
'LANGUAGES': settings.LANGUAGES,
'LANGUAGE_CODE': translation.get_language(),
'LANGUAGE_BIDI': translation.get_language_bidi(),
}
Make sure that you're using a RequestContext for your template rendering, not a plain Context, or it won't work.
Tested with Django==1.11.2.
Enable I18N and employ i18n template context processor.
# setings.py
USE_I18N = True
# ...
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
# ...
'django.template.context_processors.i18n',
# ...
],
},
},
]
And then it's simple in the template.
# template.html
{% load i18n %}
{{ LANGUAGE_CODE }}
But use render(), not render_to_response(), in your view function so the LANGUAGE_CODE variable is accessible in the template:
render_to_response()
This function preceded the introduction of render() and works
similarly except that it doesn’t make the request available in the
response. It’s not recommended and is likely to be deprecated in the
future.

Django: sorl-thumbnail and easy-thumbnail in same project

I'm working on and project that uses two separate modular Django apps. However, one app requires easy-thumbnails and the other requires sorl-thumbnails. Unfortunately, the two thumbnail libraries make use of the template tag syntax {% load thumbnail %}, so they clash and break when a template using them tries to render.
Are there any approaches to solve this type of clash? (For example, a template option does to the effect of {% load thumbnail as easy_thumbnail %}). Am I going to have to fork one of the apps and replace one of the thumbnail libraries with another? If so, which should I choose to go with?
Thank you for considering my question,
Joe
In Django 1.9, you can use the libraries option of DjangoTemplates to include a tag library under a specified name. In the example below, the thumbnail library from sorl.thumbnail is included under the name sorl_thumbnail.
Note: the templatetag itself is not changed within the template... ie. remains thumbnail
Usage:
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "foo", "templates")],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries': {
'sorl_thumbnail': 'sorl.thumbnail.templatetags.thumbnail',
},
},
},
]
your_template.html
{% load sorl_thumbnail %}
{% thumbnail mymodel.image "640x480" crop="center" as im %}
<img src="{{ im.url }}" width="{{im.width}}" height="{{im.height}}"/>
{% endthumbnail %}
Sure, just write your own stub easy_thumbnail wrapper...
Create a thumbnailtags package in one of your django apps...
...making sure it's got an empty __init__.py
In thumbnailtags/easy_thumbnail.py do something like:
from django.template import Library
from easy_thumbnails.templatetags import thumbnail
register = Library()
def easy_thumbnail(parser, token):
return thumbnail(parser, token)
register.tag(easy_thumbnail)
Use {% load easy_thumbnail %}
Note:
You might also be able to do 'import thumbnail as easy_thumbnail, and skip the def easy_thumbnail bit, tho I've not tried that.
This blog link shows how to handle this.
https://timmyomahony.com/blog/using-sorl-thumbnail-and-easy-thumbnails-same-template/
(previously
http://timmyomahony.com/blog/2012/10/22/using-sorl-thumbnail-and-easy-thumbnails-same-template/)
UPDATE 2015
I had to do the following modifications to Tom Christie's answer in order to get this to work:
create a templatetags package in one of you local apps. It is important to name it templatetags. See django docs for template tags.
... make sure it has an __init__.py, empty or not.
In templatetags/easy_thumbnail.py do this:
from django.template import Library
from easy_thumbnails.templatetags import thumbnail
register = Library()
def easy_thumbnail(parser, token):
return thumbnail.thumbnail(parser, token) # the important bit
register.tag(easy_thumbnail)
Use {% load easy_thumbnail %} or - load easy_thumbnail with pyjade