Чи можу я отримати доступ до констант у 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.