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

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

{{CONSTANT_NAME}}

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

14 ответов


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

если вы ищете доступ к другие константы в настройках, а затем просто распакуйте константы, которые вы хотите, и добавьте их в контекстный словарь, который вы используете в своей функции просмотра, например:

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


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

вот так:

  1. сделать 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}
    
  2. добавить вашу контекста процессора в settings.py:

    TEMPLATES = [{
        # whatever comes before
        'OPTIONS': {
            'context_processors': [
                # whatever comes before
                "your_app.context_processors.admin_media",
            ],
        }
    }]
    
  3. использовать RequestContext в вашей просмотр для добавления контекстных процессоров в шаблон. The render ярлык делает это автоматически:

    from django.shortcuts import render
    
    def my_view(request):
        return render(request, "index.html")
    
  4. и, наконец, в вашем шаблоне:

    ...
    <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',
]

шаблон.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" %}

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


мне нравится решение Берислава, потому что на простых сайтах оно чистое и эффективное. Что мне не нравится, так это волей-неволей выставлять все константы настроек. В итоге я сделал вот что:--3-->

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 это!--10--> (чтобы создать свой собственный тег) немного.

сначала создайте файл 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 - ... Ниже приведен непроверенный пример того, как можно автоматически построить контекстный словарь из всех атрибутов верхнего регистра 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',
...
)

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

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

app/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/


добавление ответа с полными инструкциями по созданию пользовательского тега шаблона, который решает это, с 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" %}

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


и 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")

Я нашел, что это самый простой подход для Django 1.3:

  1. views.py

    from local_settings import BASE_URL
    
    def root(request):
        return render_to_response('hero.html', {'BASE_URL': BASE_URL})
    
  2. герой.HTML-код

    var BASE_URL = '{{ JS_BASE_URL }}';
    

если бы мы сравнивали теги контекста и шаблона в одной переменной, то знание более эффективного варианта могло бы быть полезным. Однако вам может быть лучше окунуться в Настройки только из шаблонов, которым нужна эта переменная. В этом случае нет смысла передавать переменную во все шаблоны. Но если вы отправляете переменную в общий шаблон, такой как база.html шаблон, тогда это не имело бы значения в качестве базы.html-шаблон отображается по каждому запросу, поэтому вы можно использовать любой из методов.

Если вы решили пойти с параметром template tags, то используйте следующий код, поскольку он позволяет передать по умолчанию value in, на всякий случай, если рассматриваемая переменная не определена.

пример: 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)