Могу ли я получить доступ к константам в settings.py из шаблонов в Django?

У меня есть некоторые вещи в settings.py, которые я хотел бы получить от шаблона, но я не могу понять, как это сделать. Я уже пробовал

{{CONSTANT_NAME}}

но это, похоже, не работает. Возможно ли это?

Ответ 1

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 }}.

Ответ 2

Если это значение, которое вы хотели бы иметь для каждого запроса и шаблона, более целесообразно использовать контекстный процессор.

Вот как:

  • Создайте файл 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>
    ...
    

Ответ 3

Я считаю, что самый простой подход - это единственный шаблонный тег:

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" %}

Ответ 4

Отъезд 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>

Ответ 5

Другой способ сделать это - создать собственный тег шаблона, который позволит вам выгружать значения из настроек.

@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" %}

чтобы распечатать его на любой странице, не перепрыгивая через обручи контекстных процессоров.

Ответ 6

Мне нравится решение 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" %}

Это защищает любые константы, которые вы не указали из использования в шаблоне, и если вы хотите получить действительно фантазию, вы можете установить кортеж в настройках и создать более одного тега шаблона для разных страниц, приложений или областей, и просто объединить локальный кортеж с корневым набором настроек по мере необходимости, а затем составить представление списка, чтобы узнать, приемлемо ли значение.
Я согласен, что на сложном сайте это немного упрощенно, но есть ценности, которые были бы хороши для универсального использования в шаблонах, и это, похоже, работает хорошо. Спасибо Бериславу за оригинальную идею!

Ответ 7

Я улучшил 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}}.

Ответ 8

Приведенный выше пример из 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',
...
)

Ответ 9

Добавление ответа с полными инструкциями по созданию настраиваемого тега шаблона, который решает это, с помощью Django 2. 0+

В папке приложения создайте папку с именем templatetags. В нем создайте __init__.py и custom_tags.py:

Custom tags folder structure

В 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" %}

Это решение не будет работать с массивами, но если вам нужно, вы можете добавить много логики в свои шаблоны.

Ответ 10

Если вы используете представление на основе класса:

#
# 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 }}

Ответ 11

Если кто-то найдет этот вопрос, как я, я опубликую свое решение, которое работает на 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 %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}

См. Документацию Django о том, как создавать собственные теги шаблонов здесь: https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/

Ответ 12

Добавьте этот код в файл с именем 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).

Ответ 13

Я нашел, что это самый простой подход для 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 }}';
    

Ответ 14

Оба 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")

Ответ 15

Если бы мы сравнивали теги контекста и шаблона с одной переменной, то знание более эффективного варианта могло бы быть 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)