簡體   English   中英

我可以從 Django 中的模板訪問 settings.py 中的常量嗎?

[英]Can I access constants in settings.py from templates in Django?

我在 settings.py 中有一些我希望能夠從模板訪問的東西,但我不知道該怎么做。 我已經試過了

{{CONSTANT_NAME}}

但這似乎不起作用。 這可能嗎?

如果您希望每個請求和模板都有一個值,則使用上下文處理器更合適。

就是這樣:

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

我發現最簡單的方法是單個自定義模板標簽

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 內置的通用視圖或在render_to_response快捷函數中傳遞上下文實例關鍵字參數,Django 會提供對模板的某些常用設置常量的訪問,例如settings.MEDIA_URL和一些語言設置。 以下是每種情況的示例:

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

查看django-settings-export (免責聲明:我是這個項目的作者)。

例如...

$ pip install django-settings-export

設置.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" %}

將其打印在任何頁面上,而無需跳過上下文處理器箍。

我喜歡 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" %}

這可以保護您未命名的任何常量在模板中使用,如果您想變得真正花哨,您可以在設置中設置一個元組,並為不同的頁面、應用程序或區域創建多個模板標簽,只需根據需要將本地元組與設置元組組合,然后進行列表理解以查看該值是否可接受。
我同意,在一個復雜的網站上,這有點簡單,但有些值在模板中普遍存在會很好,這似乎很好用。 感謝 Berislav 的原創想法!

使用 Django 2.0+ 添加一個帶有完整說明的答案,用於創建解決此問題的自定義模板標簽

在您的應用程序文件夾中,創建一個名為templatetags的文件夾。 在其中創建__init__.pycustom_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 文檔中關於簡單標簽的部分

然后,您需要通過在您將使用它的任何模板中加載此文件,使 Django 知道這個(以及任何其他)自定義標記。 就像你需要加載內置的靜態標簽一樣:

{% load custom_tags %}

加載后,它可以像任何其他標簽一樣使用,只需提供您需要返回的特定設置。 因此,如果您的設置中有 BUILD_VERSION 變量:

{% get_setting "BUILD_VERSION" %}

此解決方案不適用於數組,但如果您需要,您可能會在模板中加入很多邏輯。

注意:一個更干凈和故障安全的解決方案可能是制作一個自定義上下文處理器,您可以在其中將所需的設置添加到所有模板都可用的上下文中。 通過這種方式,您可以降低錯誤地在模板中輸出敏感設置的風險。

將此代碼添加到名為context_processors.py的文件中:

from django.conf import settings as django_settings


def settings(request):
    return {
        'settings': django_settings,
    }

然后,在您的設置文件中,在TEMPLATES'context_processors'設置中包含一個路徑,例如'speedy.core.base.context_processors.settings' (帶有您的應用程序名稱和路徑)。

(您可以看到例如settings/base.pycontext_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,
    }

稍微改進了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 ...表示法的優點在於,它可以通過簡單的{{my_fqdn}}blocktrans塊中輕松使用。

如果使用基於類的視圖:

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

應用程序/模板標簽/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/

上面來自 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',
...
)

我發現這是 Django 1.3 最簡單​​的方法:

  1. 視圖.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 }}';

對於那些想使用帶有if標簽的@Berislav 方法(自定義模板標簽)的人:

/app/templatetags/my_settings.py:

from django import template
from django.conf import settings

register = template.Library()

@register.simple_tag
def settings_value(name):
    return getattr(settings, name, "")

模板文件:

<!-- Load your tags -->
{% load my_settings %}
{% settings_value 'ENABLE_FEATURE_A' as ENABLE_FEATURE_A %}

{% if ENABLE_FEATURE_A %}
<!-- Feature A stuffs -->
{% endif %}

更完整的實現。

/項目/設置.py

APP_NAME = 'APP'

/app/templatetags/settings_value.py

from django import template
from django.conf import settings
 
register = template.Library()
 
@register.simple_tag
def settings_value(name):
    return getattr(settings, name, "")

/應用程序/模板/索引.html

<!DOCTYPE html>
{% load static %}
{% load settings_value %}
<head>
    <title>{% settings_value "APP_NAME" %}</title>
...

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

如果我們要在單個變量上比較上下文與模板標簽,那么了解更有效的選項可能會有所幫助。 但是,您最好僅從需要該變量的模板中深入了解設置。 在這種情況下,將變量傳遞給所有模板是沒有意義的。 但是,如果您將變量發送到通用模板(例如 base.html 模板)中,那么就沒有關系了,因為 base.html 模板會在每個請求上呈現,因此您可以使用任一方法。

如果您決定使用模板標簽選項,請使用以下代碼,因為它允許您傳入默認值,以防萬一有問題的變量未定義。

示例:get_from_settings my_variable 作為 my_context_value

示例:get_from_settings my_variable my_default as 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)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM