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

328

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

{{CONSTANT_NAME}}

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

  • 0
    Если вы ищете, как передать параметр каждому ответу, посмотрите ответ bchunn о контекстных процессорах.
  • 0
    Ответ @jkbrzt - это готовое решение, которое быстро и легко решает эту проблему. Будущие читатели должны взглянуть на этот stackoverflow.com/a/25841039/396005 за принятый ответ
Теги:
django-templates
django-settings

15 ответов

152
Лучший ответ

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

  • 65
    Стоит отметить, что конкретные значения, добавляемые с помощью RequestContext, зависят от значения TEMPLATE_CONTEXT_PROCESSORS. Таким образом, если вы хотите, чтобы дополнительные значения передавались повсюду, просто напишите свой собственный контекстный процессор и добавьте его в TEMPLATE_CONTEXT_PROCESSORS.
  • 0
    Точка согласованности в общих представлениях и во многих основных и дополнительных приложениях, дополнительный контекст называется extra_context, и очень часто он включается в аргументы представления.
Показать ещё 4 комментария
366

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

Вот как:

  • Создайте файл 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>
    ...
    
  • 0
    Недостатком этого подхода является то, что вам нужно явно связать конкретные параметры в settings.py, которые вы хотите быть доступными для средства визуализации контекста. Я мог бы вообразить решение, которое использовало бы соглашение об атрибутах верхнего регистра в settings.py и автоматически строило контекст. Я добавлю пример ниже в качестве отдельного ответа.
  • 48
    это выглядит больно. почему так много обручей, чтобы захватить переменную?
Показать ещё 12 комментариев
221

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

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" %}
  • 15
    Мне нравится иметь доступ по требованию к любому параметру в шаблонах, и это обеспечивает это элегантно. Это действительно намного лучше, чем другие ответы, если вы часто будете использовать различные настройки в своих шаблонах: 1) Принятый ответ несовместим или неуклюж с представлениями на основе классов. 2) При использовании решения для процессора контекста с избыточным голосованием вам нужно будет указать отдельные параметры (или все), и оно будет выполняться для каждого отдельного запроса, который отображает шаблон - неэффективно! 3) Это проще, чем более сложный тег выше.
  • 14
    @ BenRoberts Я согласен, что это элегантное решение ... но только для крошечных проектов с одним разработчиком, который делает все. Если у вас есть отдельные люди / команды для проектирования и разработки, то это решение, вероятно, худшее . Что мешает дизайнеру злоупотреблять этим тегом, например: {% settings_value "DATABASES" %} ? Этот вариант использования должен прояснить, почему настройки не доступны в шаблонах для начала.
Показать ещё 9 комментариев
79

Отъезд 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>
  • 0
    И обратите внимание, что в ваших представлениях вам нужно использовать render а не render_to_response
  • 0
    У меня есть аналогичное требование для чтения значений из настроек в шаблонах, но я получаю 500 ошибок, когда я добавляю 'django_settings_export.settings_export' в файл настроек. Можете ли вы предложить, что я делаю здесь неправильно
Показать ещё 1 комментарий
40

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

@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
    Я думаю, что это самое элегантное решение, так как оно работает как dropin без изменения кода.
  • 1
    @flyingsheep Что вы имеете в виду "без изменения кода"?
Показать ещё 9 комментариев
22

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

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

  • 5
    почему бы просто, if name in ALLOWABLE_VALUES: ...
  • 0
    Потому что я думал, что я умен, и хотел, чтобы подстроки не запускали настройки var. ;-) Возвращение, вероятно, должно быть: return getattr (settings, is_allowable, '')
Показать ещё 3 комментария
11

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

7

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

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

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

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

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

Изображение 915

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

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

3

Если кто-то найдет этот вопрос, как я, то я опубликую свое решение, которое работает на 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/

  • 1
    спасибо, хорошо работает с Django 1.11, а также :)
2

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

1

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

Если бы мы сравнивали теги контекста и шаблона с одной переменной, то знание более эффективного варианта могло бы быть 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)
  • 0
    Или вы можете использовать SITE_EXTRA_CONTEXT_DICT в Finalware, чтобы сделать это для вас.
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню