У меня есть некоторые вещи в settings.py, которые я хотел бы получить от шаблона, но я не могу понять, как это сделать. Я уже пробовал
{{CONSTANT_NAME}}
но это, похоже, не работает. Возможно ли это?
У меня есть некоторые вещи в settings.py, которые я хотел бы получить от шаблона, но я не могу понять, как это сделать. Я уже пробовал
{{CONSTANT_NAME}}
но это, похоже, не работает. Возможно ли это?
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
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'django_settings_export.settings_export',
],
},
},
]
MY_CHEESE = 'Camembert';
SETTINGS_EXPORT = [
'MY_CHEESE',
]
<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" %}
чтобы распечатать его на любой странице, не перепрыгивая через обручи контекстных процессоров.
Мне нравится решение Berislav, потому что на простых сайтах оно чистое и эффективное. То, что мне не нравится, - это подвергать все настройки константам волей-неволей. Так что я закончил делать это:
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" %}
Это защищает любые константы, которые вы не указали из использования в шаблоне, и если вы хотите получить действительно фантазию, вы можете установить кортеж в настройках и создать более одного тега шаблона для разных страниц, приложений или областей, и просто объединить локальный кортеж с корневым набором настроек по мере необходимости, а затем составить представление списка, чтобы узнать, приемлемо ли значение.
Я согласен, что на сложном сайте это немного упрощенно, но есть ценности, которые были бы хороши для универсального использования в шаблонах, и это, похоже, работает хорошо.
Спасибо Бериславу за оригинальную идею!
Я улучшил chrisdew answer (чтобы создать собственный тег) немного.
Сначала создайте файл 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}}
.
Приведенный выше пример из bchhun хорош, за исключением того, что вам нужно явно создать свой контекстный словарь из settings.py. Ниже приведен пример UNTESTED того, как вы можете автоматически создавать словарь контекста из всех атрибутов верхнего регистра 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',
...
)
Добавление ответа с полными инструкциями по созданию настраиваемого тега шаблона, который решает это, с помощью 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" %}
Это решение не будет работать с массивами, но если вам нужно, вы можете добавить много логики в свои шаблоны.
Если вы используете представление на основе класса:
#
# 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" %}
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 %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}
См. Документацию Django о том, как создавать собственные теги шаблонов здесь: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/
Добавьте этот код в файл с именем 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).
Я нашел, что это самый простой подход для 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:
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")
Если бы мы сравнивали теги контекста и шаблона с одной переменной, то знание более эффективного варианта могло бы быть benificial. Однако вам может быть лучше окунуться в настройки только из шаблонов, которые нуждаются в этой переменной. В этом случае нет смысла передавать переменную во все шаблоны. Но если вы отправляете переменную в общий шаблон, такой как шаблон base.html, то это не имеет значения, поскольку шаблон base.html отображается по каждому запросу, поэтому вы можете использовать оба метода.
Если вы решите пойти с параметром тегов шаблонов, используйте следующий код, так как он позволяет передать значение по умолчанию, на случай, если переменная в вопросе undefined.
Пример: get_from_settings my_variable как my_context_value
Пример: get_from_settings my_variable my_default как 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)