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


367

我希望通过模板访问settings.py中的一些内容,但是我不知道该怎么做。我已经试过了

{{CONSTANT_NAME}}

但这似乎不起作用。这可能吗?


如果您正在寻找如何将设置传递给每个答案,请查看bchunn关于上下文处理器的答案
Zags

1
@jkbrzt的答案是一种预先打包的解决方案,可以快速轻松地解决此问题。未来的读者应该看看这个stackoverflow.com/a/25841039/396005,以接受的答案
Bron Davies

Answers:


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。
卡尔·梅耶

在通用视图以及许多核心和contrib应用程序中,关于一致性的一点是,附加上下文称为extra_context,并且通常将其包含在视图的参数中。
苏联

“ Django提供了对模板的某些经常使用的设置常量的访问,例如settings.MEDIA_URL”。尽管我可能使用的是错误的,但这似乎在Django 1.3中不起作用。是否有任何有关此功能的文档?
SystemParadox

1
@asofyan是,添加创建一个自定义模板上下文处理器,并在settings.py中添加到TEMPLATE_CONTEXT_PROCESSORS。
Paolo

14
django-settings-export注意避免在每个视图中编写此代码。
qris 2014年

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函数,就可以在您将要创建的每个View中访问该变量。您始终可以在每个视图中手动获取设置变量。我会随时选择一个可重用的上下文处理器,而不是良好的复制粘贴。
bchhun 2012年

5
尽我所能避免在任何地方复制/粘贴。(项目内的)每个应用程序都需要一个context_processor.py吗,有没有办法为所有这些构建一个context_processor?
Mark Essel

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 2014年

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
“我们都同意这里的成年人”
2014年

11
请原谅我成为新手。您将此代码放在哪里?Views.py?还是在新文件上?
Noel Llevares 2014年

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

我对从模板中的设置中读取值有类似的要求,但是在设置文件中添加“ django_settings_export.settings_export”时出现500错误。您能建议我在这里做错什么吗
Piyush Sahu

3
现在是2019年,我正在项目中使用它。谢谢!
sivabudh

1
我同意@sivabudh。这对我来说也是最好的解决方案,因为1.它是集中式的,这意味着我不需要额外的文件夹和文件,2.我可以在模板中看到设置名称空间,这对于获取许多应用程序的引用非常有帮助。
ywiyogo '19

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
我认为这是最优雅的解决方案,因为它无需修改代码即可作为dropin使用。
飞羊

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

感谢克里斯的帮助,添加了一个带有templatetags子目录(包括custom_template_filters)的mutil应用。仍然在homepage.html中出现错误“无效的块标记:'value_from_settings',预期为'endblock'或'endblock banner'”
Mark Essel 2012年

我认为这与“显式比隐式更好”相反,您可以使用上下文装饰器版本来选择要公开的设置。
sjh 2012年

28

我喜欢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的初衷!


5
为什么不简单if name in ALLOWABLE_VALUES: ...
frnhr 2014年

因为我以为自己很聪明,所以想防止子字符串触发设置var。;-)返回值可能应该是:return getattr(settings,is_allowable,'')
MontyThreeCard 2014年

5
只是为了向所有想知道的人澄清:'val' in ('val_first', 'second_val',)is False,这里没有子字符串问题。
frnhr

2
我如何在if声明中使用它?我想检查一下DEBUG
2015年


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+,添加包含创建可解决此问题的自定义模板标签的完整说明的答案

在您的应用程序文件夹中,创建一个名为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" %}

该解决方案不适用于数组,但是如果需要,可以在模板中增加很多逻辑。

注意:更干净,更安全的解决方案可能是制作一个自定义上下文处理器,在其中将所需的设置添加到所有模板可用的上下文中。这样,您可以减少在模板中错误输出敏感设置的风险。


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

(例如,您可以查看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,
    }

1
昨天,我遇到了这个问题,找到了这个帖子,然后是2个帖子和一个博客帖子,觉得每个帖子都太过复杂了(不幸的是,我没有做到这一点,可耻的是)。因此,我最终推出了自己的解决方案,正是这种解决方案。我刚回来,是因为当^^^ 3行功能和1行更改settings.py时,人们一直在建议插件和完整的lotta代码。
DXM

@DXM谢谢!
乌里

实际上,我的解决方案将模板的所有设置都公开了,包括诸如之类的敏感信息SECRET_KEY。黑客可能会滥用此功能以在模板中显示此类信息。
乌里

我更新了答案。
乌里

好...很好,现在我的网站也有同样的问题:)但是...我可能会遗漏一些东西,但是我们确定有问题吗?模板本质上与您网站的源代码相同,不是吗?它们存储在服务器端,无法直接从前端访问。如果黑客可以更改模板,则此时他们可以更改任何.py文件。
DXM

8

上面来自bchhun的示例很好,除了您需要从settings.py显式构建上下文字典。下面是一个未经测试的示例,该示例说明如何从settings.py的所有大写属性(例如:“ ^ [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 '19

感谢@ 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/zh-CN/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模板在每次请求时都会呈现,因此可以使用这两种方法。

如果您决定使用模板标签选项,请使用以下代码,因为它允许您传递 默认值值,以防万一变量inquestion未定义。

示例: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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.