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

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

我在settings.py中有一些东西,我希望能够从模板访问,但我无法弄清楚如何做到这一点。 我已经试过了

1
{{CONSTANT_NAME}}

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


如果它是您想要的每个请求和价值的值。模板,使用上下文处理器更合适。

这是如何做:

  • 在app目录中创建一个context_processors.py文件。假设我想在每个上下文中都有ADMIN_PREFIX_VALUE值:

    1
    2
    3
    4
    5
    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}
  • 将您的上下文处理器添加到settings.py文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    TEMPLATES = [{
        # whatever comes before
        'OPTIONS': {
            'context_processors': [
                # whatever comes before
               "your_app.context_processors.admin_media",
            ],
        }
    }]
  • 在视图中使用RequestContext在模板中添加上下文处理器。 render快捷键自动执行此操作:

    1
    2
    3
    4
    from django.shortcuts import render

    def my_view(request):
        return render(request,"index.html")
  • 最后,在你的模板中:

    1
    2
    3
    ...
    path to admin media
    ...

  • 我发现最简单的方法是单个模板标记:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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,"")

    用法:

    1
    {% settings_value"LANGUAGE_CODE" %}


    如果您使用django内置的通用视图或在render_to_response快捷方式函数中传入上下文实例关键字参数,Django可以访问模板的某些常用设置常量,例如settings.MEDIA_URL和一些语言设置。以下是每个案例的示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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 }}等。

    如果您正在寻找设置中其他常量的访问权限,那么只需解压缩您想要的常量并将它们添加到您在视图函数中使用的上下文字典中,如下所示:

    1
    2
    3
    4
    5
    6
    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


    查看django-settings-export(免责声明:我是这个项目的作者)。

    例如...

    1
    $ pip install django-settings-export

    settings.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    TEMPLATES = [
        {
            'OPTIONS': {
                'context_processors': [
                    'django_settings_export.settings_export',
                ],
            },
        },
    ]

    MY_CHEESE = 'Camembert';

    SETTINGS_EXPORT = [
        'MY_CHEESE',
    ]

    template.html

    1
    var MY_CHEESE = '{{ settings.MY_CHEESE }}';


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    @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))

    然后你可以使用:

    1
    {% value_from_settings"FQDN" %}

    在任何页面上打印它,而不跳过上下文处理器箍。


    我喜欢Berislav的解决方案,因为在简单的网站上,它是干净而有效的。我不喜欢的是无所不在地暴露所有设置常量。所以我最终做的是这样的:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    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 ''

    用法:

    1
    {% settings_value"CONSTANT_NAME_1" %}

    这可以保护您未在模板中使用的任何常量,如果您想真正了解,可以在设置中设置元组,并为不同的页面,应用或区域创建多个模板标记,并简单地根据需要将本地元组与设置元组组合,然后执行列表推导以查看该值是否可接受。
    我同意,在一个复杂的网站上,这有点过于简单,但有一些值很高兴在模板中普遍使用,这看起来效果很好。
    感谢Berislav最初的想法!


    我改进了chrisdew的答案(创建你自己的标签)。

    首先,创建文件yourapp/templatetags/value_from_settings.py,在其中定义自己的新标记value_from_settings

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    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

    您可以通过以下方式在模板中使用此标记:

    1
    2
    3
    {% load value_from_settings %}
    [...]
    {% value_from_settings"FQDN" %}

    或通过

    1
    2
    3
    {% load value_from_settings %}
    [...]
    {% value_from_settings"FQDN" as my_fqdn %}

    as ...表示法的优点在于,它可以通过简单的{{my_fqdn}}blocktrans块中轻松使用。


    使用Django 2.0+添加一个答案,其中包含创建解决此问题的自定义模板标记的完整说明

    在您的app-folder中,创建一个名为templatetags的文件夹。在其中,创建__init__.py和custom_tags.py:

    Custom tags folder structure

    在custom_tags.py中创建一个自定义标记函数,该函数提供对设置常量中任意键的访问:

    1
    2
    3
    4
    5
    6
    7
    8
    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知道此(以及任何其他)自定义标记。就像你需要加载内置静态标记一样:

    1
    {% load custom_tags %}

    加载后,它可以像任何其他标签一样使用,只需提供您需要返回的特定设置。因此,如果您的设置中有BUILD_VERSION变量:

    1
    {% get_setting"BUILD_VERSION" %}

    此解决方案不适用于数组,但如果您需要,您可能会在模板中添加许多逻辑。


    bchhun上面的例子很好,除了你需要从settings.py显式构建你的上下文字典。下面是一个UNTESTED示例,说明如何从settings.py的所有大写属性自动构建上下文字典(re:"^ [A-Z0-9 _] + $")。

    在settings.py结束时:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    _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 2.0:

    此标记将一些settings.py变量值分配给模板的变量:

    用法:{% get_settings_value template_var"SETTINGS_VAR" %}

    应用程序/ templatetags / my_custom_tags.py:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    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)

    你的模板:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    {% 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/


    将此代码添加到名为context_processors.py的文件中:

    1
    2
    3
    4
    5
    6
    7
    from django.conf import settings as django_settings


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

    然后,在您的设置文件中,在TEMPLATES'context_processors'设置中包含'speedy.core.base.context_processors.settings'(带有您的应用名称和路径)等路径。

    (你可以看看例如https://github.com/speedy-net/speedy-net/blob/staging/speedy/core/settings/base.py和https://github.com/speedy-net/speedy-净/斑点/分段/迅速/型芯/碱/ context_processors.py)。


    如果使用基于类的视图:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #
    # 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最简单的方法:

  • views.py

    1
    2
    3
    4
    from local_settings import BASE_URL

    def root(request):
        return render_to_response('hero.html', {'BASE_URL': BASE_URL})
  • hero.html

    1
    var BASE_URL = '{{ JS_BASE_URL }}';

  • 如果我们要在单个变量上比较上下文与模板标签,那么了解更有效的选项可能是有益的。但是,您最好只从需要该变量的模板中进入设置。在这种情况下,将变量传递到所有模板中是没有意义的。但是,如果您要将变量发送到公共模板(例如base.html模板),那么随着base.html模板在每个请求上呈现都无关紧要,因此您可以使用任一方法。

    如果您决定使用模板标签选项,则使用以下代码,因为它允许您传入默认值,以防未定义变量问题。

    示例:get_from_settings my_variable为my_context_value

    示例:get_from_settings my_variable my_default as my_context_value

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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)


    IanSR和bchhun都建议在设置中覆盖TEMPLATE_CONTEXT_PROCESSORS。请注意,如果您在不重新设置默认值的情况下覆盖它,则此设置有一个默认设置可能会导致一些棘手的事情。在最近的Django版本中,默认值也发生了变化。

    https://docs.djangoproject.com/en/1.3/ref/settings/#template-context-processors

    默认TEMPLATE_CONTEXT_PROCESSORS:

    1
    2
    3
    4
    5
    6
    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")