首页 文章

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

提问于
浏览
325

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

{{CONSTANT_NAME}}

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

14 回答

  • 11

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

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

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

  • 3

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

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

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

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

    如果您决定使用模板标签选项,那么请使用以下代码,因为它允许您传入 default 值,以防未定义变量问题 .

    示例: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)
    
  • 1

    我改进了chrisdew's answer(创建自己的标签) .

    首先,创建文件 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 块中使用 .

  • 4

    如果使用基于类的视图:

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

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

    请参阅Django的文档,如何在此处创建自定义模板标记:https://docs.djangoproject.com/en/2.0/howto/custom-template-tags/

  • 384

    如果's a value you'd喜欢每个请求和模板,使用context processor更合适 .

    这是如何做:

    • 在您的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}
    
    • 将您的上下文处理器添加到settings.py文件中:
    TEMPLATES = [{
        # whatever comes before
        'OPTIONS': {
            'context_processors': [
                # whatever comes before
                "your_app.context_processors.admin_media",
            ],
        }
    }]
    
    • 在视图中使用 RequestContext 在模板中添加上下文处理器 . render shortcut会自动执行此操作:
    from django.shortcuts import render
    
    def my_view(request):
        return render(request, "index.html")
    
    • 最后,在您的模板中:
    ...
    <a href="{{ ADMIN_MEDIA_URL }}">path to admin media</a>
    ...
    
  • 159

    bchhun上面的例子很好,除了你需要从settings.py显式构建你的上下文字典 . 下面是一个UNTESTED示例,说明如何从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',
    ...
    )
    
  • 0

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

    我喜欢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最初的想法!

  • 82

    我发现这是Django 1.3最简单的方法:

    • views.py
    from local_settings import BASE_URL
    
    def root(request):
        return render_to_response('hero.html', {'BASE_URL': BASE_URL})
    
    • hero.html
    var BASE_URL = '{{ JS_BASE_URL }}';
    
  • 23

    如果您使用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 .

  • 3

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

    在您的app-folder中,创建一个名为 templatetags 的文件夹 . 在其中,创建 init.pycustom_tags.py

    Custom tags folder structure

    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文档中阅读the section on simple tags .

    然后,您需要通过将此文件加载到您将使用它的任何模板中,使Django知道此(以及任何其他)自定义标记 . 就像你需要加载内置静态标记一样:

    {% load custom_tags %}
    

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

    {% get_setting "BUILD_VERSION" %}
    

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

相关问题