Чи можу я отримати доступ до констант у settings.py із шаблонів у Django?


367

У налаштуваннях.py є деякі речі, до яких я хотів би отримати доступ із шаблону, але не можу зрозуміти, як це зробити. Я вже пробував

{{CONSTANT_NAME}}

але це, здається, не працює. Чи можливо це?


Якщо ви шукаєте, як передати налаштування на кожну відповідь, подивіться відповідь bchunn щодо процесорів контексту
— Zags

1
Відповідь від @jkbrzt - це попередньо упаковане рішення, яке швидко та легко вирішує цю проблему. Майбутні читачі повинні поглянути на цей stackoverflow.com/a/25841039/396005 над прийнятою відповіддю
— Брон Девіс

Відповіді:


183

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


66
Варто зазначити, що конкретні значення, додані за допомогою RequestContext, залежать від значення TEMPLATE_CONTEXT_PROCESSORS. Таким чином, якщо ви хочете, щоб додаткові значення передавалися скрізь, просто напишіть власний контекстний процесор і додайте його до TEMPLATE_CONTEXT_PROCESSORS.
— Карл Мейєр

Точка на узгодженість, у загальних поглядах та багатьох основних програмах для основних та додаткових додатків контекст називається extra_context, і дуже часто він включається в аргументи подання.
— Радянський

"Django забезпечує доступ до певних констант налаштувань, що часто використовуються, до шаблону, таких як налаштування.MEDIA_URL". Схоже, це не працює в Django 1.3, хоча, мабуть, я його неправильно використовую. Чи є документація на цю функцію?
— SystemParadox

1
@asofyan так, додайте створити власний процесор контексту шаблону та додайте до TEMPLATE_CONTEXT_PROCESSORS у settings.py.
— Паоло

14
Подивіться на те, django-settings-exportщоб уникнути необхідності писати цей код у кожному режимі.
— qris

441

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

Ось як:

  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у своєму поданні, щоб додати ваші контекстні процесори у ваш шаблон. 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>
    ...
    

32
@MarkEssel Ці обручі зроблені таким чином, щоб змінна була доступна в кожному перегляді, який ви будете робити, доки вона використовує функцію RequestContext. Ви завжди могли вручну змінювати параметри змін у кожному перегляді. Я б вибирав процесор контексту для багаторазового використання замість гарного ol 'Copy & paste.
— bchhun

5
роблю все можливе, щоб уникати копіювання / вставки скрізь, де це можливо. чи потребує кожен додаток (у рамках проекту) контекст_процесор.py, чи існує спосіб побудувати один контекстний процесор для всіх?
— Марк Ессел

10
@bchhun Я щойно тестував (Django 1.3): обмін контекстним процесором між додатками працює чудово. :-) Я поставив context_process.pyпоруч зі своїм settings.pyфайлом і додав "context_processors.admin_media"до свого TEMPLATE_CONTEXT_PROCESSORSсписку. Також ви можете додати примітку у відповідь про те, що значення TEMPLATE_CONTEXT_PROCESSORS за замовчуванням не порожнє, тому якщо будь-який існуючий код використовує будь-яке значення, встановлене цими процесорами за замовчуванням, вони не працюватимуть, якщо ви не додасте їх назад до списку прямо.
— MiniQuark

5
@MarkEssel Це зовсім не боляче - він просто все прописав. Це дійсно лише 6 коротких рядків (кроки 1 і 2). Кроки 3 і 4 або їх еквівалент необхідні для більшості шаблонів у будь-якому випадку.
— Рік Вестера

2
Станом на Django 1.3, ви можете використовувати renderярлик, щоб уникнути явного включення RequestContext
— yndolok

269

Я вважаю найпростішим підходом єдиний тег шаблону :

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

17
Мені подобається мати доступ на замовлення до будь-яких налаштувань у шаблонах, і це забезпечує це елегантно. Це дійсно набагато краще, ніж інші відповіді, якщо ви часто використовуєте різні налаштування у своїх шаблонах: 1) Прийнята відповідь несумісна або незграбна з класовими видами. 2) За допомогою контекстного рішення процесора за заголосованим шаблоном, вам потрібно буде вказати окремі параметри (або всі), і він запускатиметься для кожного запиту, який робить шаблон - неефективним! 3) Його простіше, ніж складніший тег, описаний вище.
— Бен Робертс

16
@BenRoberts Я згоден, що це елегантне рішення ... але тільки для крихітних проектів з одним розробником, який робить все. Якщо у вас є окремі люди / команди для розробки та розробки, то це рішення, мабуть, найгірше . Що заважає дизайнеру не зловживати цим тегом чимось на кшталт {% settings_value "DATABASES" %}:? Цей випадок використання повинен дати зрозуміти, чому налаштування недоступні в шаблонах для початку.
— mkoistinen

23
"Ми всі тут погоджуємось із дорослими"
— 14-14

11
Вибачте мене за те, що я новачок. Куди ви кладете цей код? Views.py? Або на новий файл?
— Ноель Ллеварес

13
Щоб зрозуміти іншим людям, вам потрібно: 1) створити templatetagsпапку всередині додатка із порожнім __init__.pyфайлом і цим кодом як settings.pyу цій папці. 2) у своєму шаблоні ви додасте, {% load settings %}а потім використовуйте новий тег!
— даміо

95

Перевірте 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>

1
І зауважте, що у своїх поглядах вам потрібно користуватися, renderа неrender_to_response
— Everett Toews

У мене є аналогічна вимога читати значення, встановлені в шаблонах, але я отримую 500 помилок, коли додаю "django_settings_export.settings_export" у налаштування файлу. Чи можете ви підказати, що я тут роблю неправильно
— Піюш Саху

3
Це 2019 рік, і я використовую його у своєму проекті. Дякую!
— sivabudh

1
Я згоден з @sivabudh. Це для мене також найкраще рішення, тому що 1. Це централізоване, що означає, що мені не потрібні додаткові папки та файли, 2. Я можу побачити область імен параметрів у своєму шаблоні, що дуже корисно для отримання посилань багатьох програм.
— ywiyogo

46

Інший спосіб зробити це - створити спеціальний тег шаблону, який дозволяє виводити значення з налаштувань.

@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
Я думаю, що це найелегантніше рішення, оскільки воно працює як дроплін, не змінюючи код.
— літаючі вівці

1
що ви можете залишити решту програми без змін: ви додаєте один тег і використовуєте його, замість того, щоб додавати контекстні процесори (це означає, що вам потрібно редагувати свою програму в декількох місцях)
— літаючі вівці

2
@Mark - у produi / src / produi / template_utils / templatetags / custom_template_filters.py template_utils посилається з settings.py INSTALLED_APPS - також див. Docs.djangoproject.com/en/dev/howto/custom-template-tags
— fadedbee

оцінивши допомогу, додав мутильований додаток із підкаталогом тегів шаблонів, включаючи custom_template_filters. Все ще виникає помилка в homepage.html "Недійсний тег блоку: 'value_from_settings', очікуваний 'endblock' або 'банер endblock'"
— Марк Ессел

Я думаю, що це суперечить "явному краще, ніж неявному", використовуючи версію декоратора контексту, ви вибираєте саме те, які параметри виставити.
— sjh

29

Мені подобається рішення Берислава, тому що на простих сайтах воно чисте та ефективне. Те, що мені НЕ подобається, - це виставляти всі константи налаштувань мимоволі. Тому я закінчила це:

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: ...
— frnhr

Тому що я думав, що я розумний, і хотів не допустити, щоб підрядки викликали налаштування var. ;-) Повернення, ймовірно, повинно бути: return getattr (параметри, є_дозволено, '')
— MontyThreeCard

5
Просто для уточнення для тих, хто цікавиться: 'val' in ('val_first', 'second_val',)чи Falseнемає тут жодної проблеми з підрядками.
— frnhr

2
Як я можу це використати у ifзаяві? Я хочу перевірити DEBUGзначення
— AJ

Якщо комусь потрібна версія з повторним включенням gist.github.com/BrnoPCmaniak/632f56ddb907108b3d43fa862510dfca
— Filip Dobrovolný

12

Я трохи покращив відповідь 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}}.


12

Додайте відповідь із повними інструкціями щодо створення спеціального тегу шаблону, який вирішує це, за допомогою Django 2.0+

У своїй папці додатків створіть папку під назвою теги шаблонів . У ньому створіть __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.

Тоді вам потрібно повідомити Джанго про цей (та будь-який додатковий) спеціальний тег, завантаживши цей файл у будь-який шаблон, де ви його будете використовувати. Як і вам потрібно завантажити вбудований статичний тег:

{% load custom_tags %}

З завантаженим ним можна використовувати так само, як і будь-який інший тег, просто надайте конкретні настройки, які вам потрібно повернути. Отже, якщо у налаштуваннях є змінна BUILD_VERSION:

{% get_setting "BUILD_VERSION" %}

Це рішення не працюватиме з масивами, але якщо вам це потрібно, можливо, ви втручаєте багато логіки у своїх шаблонах.

Примітка. Більш чистим та безпечним рішенням, ймовірно, було б зробити спеціальний контекстний процесор, де ви додасте необхідні настройки до контексту, доступного для всіх шаблонів. Таким чином ви зменшите ризик помилково вивести чутливі настройки у ваші шаблони.


9

Додайте цей код у файл під назвою 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.

(Ви можете побачити, наприклад, налаштування / base.py та context_processors.py ).

Тоді ви можете використовувати певні налаштування в будь-якому коді шаблону. Наприклад:

{% if settings.SITE_ID == settings.SPEEDY_MATCH_SITE_ID %}

Оновлення: наведений вище код відкриває всі налаштування шаблонів, включаючи конфіденційну інформацію, таку як ваш SECRET_KEY. Хакер може зловживати цією функцією для відображення такої інформації в шаблонах. Якщо ви хочете викрити шаблони лише певних налаштувань, використовуйте замість цього код:

def settings(request):
    settings_in_templates = {}
    for attr in ["SITE_ID", ...]: # Write here the settings you want to expose to the templates.
        if (hasattr(django_settings, attr)):
            settings_in_templates[attr] = getattr(django_settings, attr)
    return {
        'settings': settings_in_templates,
    }

1
Я вчора потрапив на цю проблему, знайшов цю публікацію, потім 2 інших та повідомлення в блозі і відчув, що кожен з них був надмірно складним (на жаль, я не зробив це далеко вниз на сторінці, сором мені). Тоді я закінчила свою прокатку, яка ТОЧНО це рішення. Я щойно повернувся, тому що мене клопочуть, що люди рекомендували плагіни та цілий код лоти, коли ця ^^^ 3-рядова функція та 1-рядова зміна settings.py.
— DXM

@DXM Дякую!
— Швидкий матч

Насправді моє рішення розкриває всі параметри шаблонів, включаючи конфіденційну інформацію, таку як SECRET_KEY. Хакер може зловживати цією функцією для відображення такої інформації в шаблонах.
— Швидкий матч

Я оновив свою відповідь.
— Швидкий матч

ну ... чудово, зараз на моєму веб-сайті є така ж проблема :) Але ... я, можливо, щось не вистачає, проте чи ми впевнені, що є проблема? Шаблони по суті такі ж, як вихідний код вашого веб-сайту, чи не так? Вони зберігаються на стороні сервера та є недоступними безпосередньо з передньої частини. Якщо хакер може змінити шаблон, в цей момент вони можуть змінити будь-який .py файл.
— DXM

8

Приклад, наведений вище від 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',
...
)

8

Якщо хтось знайде це питання, як я, тоді я опублікую своє рішення, яке працює на 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 %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}

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


1
{% if settings_debug %}
— user66081

Дякую @ user66081! Змінено {% if settings_debug == True %}на запропоновані вами пропозиції{% if settings_debug %}
— NullIsNot0,

7

Якщо використовується перегляд на основі класу:

#
# 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 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. hero.html

    var BASE_URL = '{{ JS_BASE_URL }}';

1

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

1

Якби ми порівнювали теги контексту та шаблону на одній змінній, то знання більш ефективного варіанту може бути доброякісним. Однак вам може бути краще зануритися в налаштування лише з шаблонів, яким потрібна ця змінна. У цьому випадку немає сенсу передавати змінну у всі шаблони. Але якщо ви пересилаєте змінну в загальний шаблон, такий як шаблон base.html, тоді це не має значення, оскільки шаблон base.html надається при кожному запиті, тому ви можете використовувати будь-який метод.

Якщо ви вирішили перейти з опцією тегів шаблонів, тоді використовуйте наступний код, оскільки він дозволяє передати значення за замовчуванням у, на випадок, якщо питання про змінну, про яку йдеться, не було визначено.

Приклад: 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)

Або ви можете використовувати SITE_EXTRA_CONTEXT_DICTв кінцевому посуді, щоб зробити це за вас.
— un33k
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.