我可以从Django的模板中访问settings.py中的常量吗?

我有一些东西在设置。py,我想能够从模板访问,但我不知道如何做到这一点。我已经试过了

{{CONSTANT_NAME}}

但这似乎并不奏效。这可能吗?

188093 次浏览

如果它是你希望每个请求都有的值&模板,使用上下文处理器更合适。

方法如下:

  1. 在你的app目录中创建一个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. add your context processor to your settings.py file:

    TEMPLATES = [{
    # whatever comes before
    'OPTIONS': {
    'context_processors': [
    # whatever comes before
    "your_app.context_processors.admin_media",
    ],
    }
    }]
    
  3. Use RequestContext in your view to add your context processors in your template. The render shortcut does this automatically:

    from django.shortcuts import render
    
    
    def my_view(request):
    return render(request, "index.html")
    
  4. and finally, in your template:

    ...
    <a href="\{\{ ADMIN_MEDIA_URL }}">path to admin media</a>
    ...
    

如果你使用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)

现在你可以在模板中作为\{\{ favorite_color }}访问settings.FAVORITE_COLOR

另一种方法是创建一个自定义模板标签,它可以让您从设置中获取值。

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

将它打印在任何页面上,而无需跳过上下文处理器的约束。

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

我改进了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块中使用它。

我发现最简单的方法是一个自定义模板标签:

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

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模板在每次请求时都会被呈现,所以你可以使用任何一种方法。

如果你决定使用template tags选项,那么使用下面的代码,因为它允许你传入一个默认的值,以防问题变量是未定义的。

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

如果使用基于类的视图:

#
# 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 1.3最简单的方法:

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

我喜欢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的原创想法!< / p >

查看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>

如果有人像我一样发现了这个问题,那么我将发布我的解决方案,它适用于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 %}
... do something ...
{% else %}
... do other stuff ...
{% endif %}

查看Django文档中如何创建自定义模板标签:https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/

在Django 2.0+中添加了一个完整的创建自定义模板标签的答案

在你的app文件夹中,创建一个名为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'(与你的应用程序名称和路径)。

(例如,你可以看到设置/ 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,
}

对于那些想要使用@Berislav的方法(自定义模板标签)和if标签的人:

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

一个更完整的实现。

/项目/ settings.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, "")

/ app /模板/ index . html

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