Могу ли я получить доступ к константам в settings.py из шаблонов в Django?
У меня есть некоторые вещи в settings.py, к которым я бы хотел получить доступ из шаблона, но я не могу понять, как это сделать. Я уже пробовала
{{CONSTANT_NAME}}
но это не похоже на работу. Это возможно?
17 ответов
Django предоставляет доступ к некоторым часто используемым константам настроек шаблона, таким как settings.MEDIA_URL
и некоторые настройки языка, если вы используете встроенные в django универсальные представления или передаете аргумент ключевого слова экземпляра контекста в render_to_response
функция быстрого доступа. Вот пример каждого случая:
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.generic.simple import direct_to_template
def my_generic_view(request, template='my_template.html'):
return direct_to_template(request, template)
def more_custom_view(request, template='my_template.html'):
return render_to_response(template, {}, context_instance=RequestContext(request))
Оба этих представления будут иметь несколько часто используемых настроек, таких как settings.MEDIA_URL
доступны для шаблона как {{ MEDIA_URL }}
, так далее.
Если вы ищете доступ к другим константам в настройках, просто распакуйте нужные константы и добавьте их в контекстный словарь, который вы используете в своей функции представления, например так:
from django.conf import settings
from django.shortcuts import render_to_response
def my_view_function(request, template='my_template.html'):
context = {'favorite_color': settings.FAVORITE_COLOR}
return render_to_response(template, context)
Теперь вы можете получить доступ settings.FAVORITE_COLOR
в вашем шаблоне как {{ favorite_color }}
,
Если это значение, которое вы хотели бы иметь для каждого запроса и шаблона, лучше использовать контекстный процессор.
Вот как:
Делать
context_processors.py
файл в каталоге вашего приложения. Допустим, я хочу иметьADMIN_PREFIX_VALUE
значение в каждом контексте:from django.conf import settings # import the settings file def admin_media(request): # return the value you want as a dictionnary. you may add multiple values in there. return {'ADMIN_MEDIA_URL': settings.ADMIN_MEDIA_PREFIX}
добавьте ваш контекстный процессор в ваш файл settings.py:
TEMPLATES = [{ # whatever comes before 'OPTIONS': { 'context_processors': [ # whatever comes before "your_app.context_processors.admin_media", ], } }]
использование
RequestContext
по вашему мнению, чтобы добавить ваши контекстные процессоры в ваш шаблон.render
ярлык делает это автоматически:from django.shortcuts import render def my_view(request): return render(request, "index.html")
и, наконец, в вашем шаблоне:
... <a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a> ...
Я считаю, что самым простым подходом является использование одного тега шаблона:
from django import template
from django.conf import settings
register = template.Library()
# settings value
@register.simple_tag
def settings_value(name):
return getattr(settings, name, "")
Использование:
{% settings_value "LANGUAGE_CODE" %}
Проверять, выписываться django-settings-export
(отказ от ответственности: я автор этого проекта).
Например...
$ pip install django-settings-export
settings.py
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'django_settings_export.settings_export',
],
},
},
]
MY_CHEESE = 'Camembert';
SETTINGS_EXPORT = [
'MY_CHEESE',
]
template.html
<script>var MY_CHEESE = '{{ settings.MY_CHEESE }}';</script>
Еще один способ сделать это - создать собственный тег шаблона, который позволит вам вывести значения из настроек.
@register.tag
def value_from_settings(parser, token):
try:
# split_contents() knows not to split quoted strings.
tag_name, var = token.split_contents()
except ValueError:
raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
return ValueFromSettings(var)
class ValueFromSettings(template.Node):
def __init__(self, var):
self.arg = template.Variable(var)
def render(self, context):
return settings.__getattr__(str(self.arg))
Затем вы можете использовать:
{% value_from_settings "FQDN" %}
распечатать его на любой странице, не перепрыгивая через контекстные процессоры.
Мне нравится решение Берислава, потому что на простых сайтах оно чисто и эффективно. Что мне НЕ нравится, так это выставление всех констант настроек волей-неволей. Итак, что я в итоге сделал это:
from django import template
from django.conf import settings
register = template.Library()
ALLOWABLE_VALUES = ("CONSTANT_NAME_1", "CONSTANT_NAME_2",)
# settings value
@register.simple_tag
def settings_value(name):
if name in ALLOWABLE_VALUES:
return getattr(settings, name, '')
return ''
Использование:
{% settings_value "CONSTANT_NAME_1" %}
Это защищает любые константы, которые вы не назвали, от использования в шаблоне, и, если вы хотите получить действительно модные, вы можете установить кортеж в настройках и создать более одного тега шаблона для разных страниц, приложений или областей, и просто при необходимости объедините локальный кортеж с кортежем настроек, затем выполните понимание списка, чтобы увидеть, является ли значение приемлемым.
Я согласен, на сложном сайте это немного упрощенно, но есть значения, которые было бы неплохо иметь универсально в шаблонах, и это, кажется, работает хорошо. Спасибо Бериславу за оригинальную идею!
Добавление ответа с подробными инструкциями по созданию настраиваемого тега шаблона, решающего эту проблему, с помощью Django 2.0+
В вашей папке приложения создайте папку с именем templatetags. В нем создайте __init__.py и custom_tags.py:
В custom_tags.py создайте функцию пользовательского тега, которая обеспечивает доступ к произвольному ключу в константе настроек:
from django import template
from django.conf import settings
register = template.Library()
@register.simple_tag
def get_setting(name):
return getattr(settings, name, "")
Чтобы понять этот код, я рекомендую прочитать раздел о простых тегах в документации Django.
Затем вам нужно сообщить Django об этом (и любом дополнительном) пользовательском теге, загрузив этот файл в любой шаблон, где вы будете его использовать. Так же, как вам нужно загрузить встроенный статический тег:
{% load custom_tags %}
Когда он загружен, его можно использовать, как и любой другой тег, просто предоставив конкретный параметр, который вам нужно вернуть. Так что если у вас есть переменная BUILD_VERSION в ваших настройках:
{% get_setting "BUILD_VERSION" %}
Это решение не будет работать с массивами, но, если вам это нужно, вы можете использовать большую логику в своих шаблонах.
Добавьте этот код в файл с именем context_processors.py
:
from django.conf import settings as django_settings
def settings(request):
return {
'settings': django_settings,
}
А затем, в вашем файле настроек, включите путь, такой как 'speedy.core.base.context_processors.settings'
(с вашим именем приложения и путем) в 'context_processors'
настройки в TEMPLATES
,
(Вы можете увидеть, например, https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/settings/base.py и https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/base/context_processors.py).
Я немного улучшил ответ chrisdew (чтобы создать свой собственный тег).
Сначала создайте файл yourapp/templatetags/value_from_settings.py
в котором вы определяете свой новый тег value_from_settings
:
from django.template import TemplateSyntaxError, Variable, Node, Variable, Library
from yourapp import settings
register = Library()
# I found some tricks in URLNode and url from defaulttags.py:
# https://code.djangoproject.com/browser/django/trunk/django/template/defaulttags.py
@register.tag
def value_from_settings(parser, token):
bits = token.split_contents()
if len(bits) < 2:
raise TemplateSyntaxError("'%s' takes at least one " \
"argument (settings constant to retrieve)" % bits[0])
settingsvar = bits[1]
settingsvar = settingsvar[1:-1] if settingsvar[0] == '"' else settingsvar
asvar = None
bits = bits[2:]
if len(bits) >= 2 and bits[-2] == 'as':
asvar = bits[-1]
bits = bits[:-2]
if len(bits):
raise TemplateSyntaxError("'value_from_settings' didn't recognise " \
"the arguments '%s'" % ", ".join(bits))
return ValueFromSettings(settingsvar, asvar)
class ValueFromSettings(Node):
def __init__(self, settingsvar, asvar):
self.arg = Variable(settingsvar)
self.asvar = asvar
def render(self, context):
ret_val = getattr(settings,str(self.arg))
if self.asvar:
context[self.asvar] = ret_val
return ''
else:
return ret_val
Вы можете использовать этот тег в своем шаблоне через:
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" %}
или через
{% load value_from_settings %}
[...]
{% value_from_settings "FQDN" as my_fqdn %}
Преимущество as ...
примечание заключается в том, что это позволяет легко использовать в blocktrans
блокирует с помощью простого {{my_fqdn}}
,
Если используется представление на основе классов:
#
# in settings.py
#
YOUR_CUSTOM_SETTING = 'some value'
#
# in views.py
#
from django.conf import settings #for getting settings vars
class YourView(DetailView): #assuming DetailView; whatever though
# ...
def get_context_data(self, **kwargs):
context = super(YourView, self).get_context_data(**kwargs)
context['YOUR_CUSTOM_SETTING'] = settings.YOUR_CUSTOM_SETTING
return context
#
# in your_template.html, reference the setting like any other context variable
#
{{ YOUR_CUSTOM_SETTING }}
Если кто-то найдет этот вопрос, как я, я опубликую свое решение, которое работает на Django 2.0:
Этот тег назначает некоторое значение переменной settings.py переменной шаблона:
Использование: {% get_settings_value template_var "SETTINGS_VAR" %}
приложение /templatetags/my_custom_tags.py:
from django import template
from django.conf import settings
register = template.Library()
class AssignNode(template.Node):
def __init__(self, name, value):
self.name = name
self.value = value
def render(self, context):
context[self.name] = getattr(settings, self.value.resolve(context, True), "")
return ''
@register.tag('get_settings_value')
def do_assign(parser, token):
bits = token.split_contents()
if len(bits) != 3:
raise template.TemplateSyntaxError("'%s' tag takes two arguments" % bits[0])
value = parser.compile_filter(bits[2])
return AssignNode(bits[1], value)
Ваш шаблон:
{% load my_custom_tags %}
# Set local template variable:
{% get_settings_value settings_debug "DEBUG" %}
# Output settings_debug variable:
{{ settings_debug }}
# Use variable in if statement:
{% if settings_debug == True %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}
Смотрите документацию Django о том, как создавать собственные теги шаблонов здесь: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
Приведенный выше пример из bchhun хорош, за исключением того, что вам нужно явно собрать свой контекстный словарь из settings.py. Ниже приведен НЕПРОВЕРЕННЫЙ пример того, как вы можете автоматически построить контекстный словарь из всех прописных атрибутов settings.py (re: "^[A-Z0-9_]+$").
В конце settings.py:
_context = {}
local_context = locals()
for (k,v) in local_context.items():
if re.search('^[A-Z0-9_]+$',k):
_context[k] = str(v)
def settings_context(context):
return _context
TEMPLATE_CONTEXT_PROCESSORS = (
...
'myproject.settings.settings_context',
...
)
Для тех, кто хочет использовать подход @Berislav (настраиваемый тег шаблона) с
if
ярлык:
/app/templatetags/my_settings.py:
from django import template
from django.conf import settings
register = template.Library()
@register.simple_tag
def settings_value(name):
return getattr(settings, name, "")
Файл шаблона:
<!-- Load your tags -->
{% load my_settings %}
{% settings_value 'ENABLE_FEATURE_A' as ENABLE_FEATURE_A %}
{% if ENABLE_FEATURE_A %}
<!-- Feature A stuffs -->
{% endif %}
Я обнаружил, что это самый простой подход для Django 1.3:
views.py
from local_settings import BASE_URL def root(request): return render_to_response('hero.html', {'BASE_URL': BASE_URL})
hero.html
var BASE_URL = '{{ JS_BASE_URL }}';
И IanSR, и bchhun предложили переопределить TEMPLATE_CONTEXT_PROCESSORS в настройках. Имейте в виду, что этот параметр имеет значение по умолчанию, которое может вызвать некоторые неприятные вещи, если вы переопределите его, не переустанавливая значения по умолчанию. Значения по умолчанию также изменились в последних версиях Django.
https://docs.djangoproject.com/en/1.3/ref/settings/
TEMPLATE_CONTEXT_PROCESSORS по умолчанию:
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.static",
"django.contrib.messages.context_processors.messages")
Если бы мы сравнивали теги контекста и шаблона на одной переменной, то знание более эффективного варианта могло бы принести пользу. Тем не менее, вам может быть лучше окунуться в настройки только из шаблонов, которые нуждаются в этой переменной. В этом случае нет смысла передавать переменную во все шаблоны. Но если вы отправляете переменную в общий шаблон, такой как шаблон base.html, то это не имеет значения, поскольку шаблон base.html отображается при каждом запросе, поэтому вы можете использовать любой из этих методов.
Если вы решите использовать параметр тегов шаблона, используйте следующий код, поскольку он позволяет передавать значение по умолчанию, на случай, если рассматриваемая переменная не определена.
Пример: get_from_settings my_variable as my_context_value
Пример: get_from_settings my_variable my_default as my_context_value
class SettingsAttrNode(Node):
def __init__(self, variable, default, as_value):
self.variable = getattr(settings, variable, default)
self.cxtname = as_value
def render(self, context):
context[self.cxtname] = self.variable
return ''
def get_from_setting(parser, token):
as_value = variable = default = ''
bits = token.contents.split()
if len(bits) == 4 and bits[2] == 'as':
variable = bits[1]
as_value = bits[3]
elif len(bits) == 5 and bits[3] == 'as':
variable = bits[1]
default = bits[2]
as_value = bits[4]
else:
raise TemplateSyntaxError, "usage: get_from_settings variable default as value " \
"OR: get_from_settings variable as value"
return SettingsAttrNode(variable=variable, default=default, as_value=as_value)
get_from_setting = register.tag(get_from_setting)
Более полная реализация.
/проект/settings.py
APP_NAME = 'APP'
/app/templatetags/settings_value.py
from django import template
from django.conf import settings
register = template.Library()
@register.simple_tag
def settings_value(name):
return getattr(settings, name, "")
/приложение/шаблоны/index.html
<!DOCTYPE html>
{% load static %}
{% load settings_value %}
<head>
<title>{% settings_value "APP_NAME" %}</title>
...