Python 在 Django 中定义常量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4042407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:58:36  来源:igfitidea点击:

Defining Constants in Django

pythondjangoconstants

提问by Edan Maor

I want to have some constants in a Django Projects. For example, let's say a constant called MIN_TIME_TEST.

我想在 Django 项目中有一些常量。例如,假设有一个名为 的常量MIN_TIME_TEST

I would like to be able to access this constant in two places: from within my Python code, and from within any Templates.

我希望能够在两个地方访问这个常量:从我的 Python 代码中,以及从任何模板中。

What's the best way to go about doing this?

这样做的最佳方法是什么?

EDIT:To clarify, I know about Template Context Processors and about just putting things in settings.py or some other file and just importing.

编辑:澄清一下,我了解模板上下文处理器以及将内容放入 settings.py 或其他一些文件中并仅导入。

My question is, how do I combine the two approaches without violating the "Don't Repeat Yourself" rule? Based on the answers so far, here's my approach:

我的问题是,如何在不违反“不要重复自己”规则的情况下结合这两种方法?根据到目前为止的答案,这是我的方法:

I'd like to create a file called global_constants.py, which will have a list of constants (things like MIN_TIME_TEST = 5). I can importthis file into any module to get the constants.

我想创建一个名为 global_constants.py 的文件,该文件将包含一个常量列表(例如MIN_TIME_TEST = 5)。我可以import将此文件放入任何模块以获取常量。

But now, I want to create the context processor which returns all of these constants. How can I go about doing this automatically, without having to list them again in a dictionary, like in John Mee's answer?

但是现在,我想创建返回所有这些常量的上下文处理器。我怎样才能自动执行此操作,而不必像 John Mee 的回答那样在字典中再次列出它们?

采纳答案by John Mee

Both Luper and Vladimir are correct imho but you'll need both in order to complete your requirements.

Luper 和 Vladimir 都是正确的,恕我直言,但您需要两者才能完成您的要求。

  • Although, the constants don't needto be in the settings.py, you could put them anywhere and import them from that place into your view/model/module code. I sometimes put them into the __init__.pyif I don't care to have them to be considered globally relevant.

  • a context processor like this will ensure that selected variables are globally in the template scope

    def settings(request):
        """
        Put selected settings variables into the default template context
        """
        from django.conf import settings
        return {
            'DOMAIN':     settings.DOMAIN,
            'GOOGLEMAPS_API_KEY': settings.GOOGLEMAPS_API_KEY,
        }
    
  • 虽然参数并不需要是在settings.py,你可以把他们的任何地方,从地方将其导入到你的视图/模型/模块代码。__init__.py如果我不关心让它们被认为是全球相关的,我有时会将它们放入。

  • 像这样的上下文处理器将确保所选变量在模板范围内是全局的

    def settings(request):
        """
        Put selected settings variables into the default template context
        """
        from django.conf import settings
        return {
            'DOMAIN':     settings.DOMAIN,
            'GOOGLEMAPS_API_KEY': settings.GOOGLEMAPS_API_KEY,
        }
    

But this might be overkill if you're new to django; perhaps you're just asking how to put variables into the template scope...?

但是,如果您不熟悉 Django,这可能有点过头了;也许您只是在问如何将变量放入模板范围......?

from django.conf import settings

...
# do stuff with settings.MIN_TIME_TEST as you wish

render_to_response("the_template.html", { 
    "MIN_TIME_TEST": settings.MIN_TIME_TEST 
}, context_instance=RequestContext(request)

回答by devmiles.com

Consider putting it into settings.py of your application. Of course, in order to use it in template you will need to make it available to template as any other usual variable.

考虑将其放入应用程序的 settings.py 中。当然,为了在模板中使用它,您需要使它像任何其他常用变量一样可用于模板。

回答by Luper Rouch

Use context processorsto have your constants available in all templates (settings.py is a nice place to define them as Vladimir said).

使用上下文处理器让你的常量在所有模板中可用(settings.py 是一个很好的地方来定义它们,正如 Vladimir 所说)。

回答by andrei1089

In the context processor you can use something like:

在上下文处理器中,您可以使用以下内容:

import settings

context = {}
for item in dir(settings):
    #use some way to exclude __doc__, __name__, etc..
    if item[0:2] != '__':
        context[item] = getattr(settings, item)

回答by Jordan Reiter

To build on other people's answers, here's a simple way you'd implement this:

为了建立在其他人的答案的基础上,这里有一个简单的实现方法:

In your settings file:

在您的设置文件中:

GLOBAL_SETTINGS = {
    'MIN_TIME_TEST': 'blah',
    'RANDOM_GLOBAL_VAR': 'blah',
}

Then, building off of John Mee's context processor:

然后,构建John Mee 的上下文处理器

def settings(request):
    """
    Put selected settings variables into the default template context
    """
    from django.conf import settings
    return settings.GLOBAL_SETTINGS

This will resolve the DRY issue.

这将解决 DRY 问题。

Or, if you only plan to use the global settings occasionally and want to call them from within the view:

或者,如果您只打算偶尔使用全局设置并希望从视图中调用它们:

def view_func(request):
    from django.conf import settings
    # function code here
    ctx = {} #context variables here
    ctx.update(settings.GLOBAL_SETTINGS)
    # whatever output you want here

回答by desfido

Variant on John Mee's last part, with a little elaboration on the same idea Jordan Reiter discusses.

John Mee 的最后一部分的变体,对 Jordan Reiter 讨论的同一想法进行了一些详细说明。

Suppose you have something in your settings akin to what Jordan suggested -- in other words, something like:

假设您的设置中有一些类似于 Jordan 建议的内容——换句话说,类似于:

GLOBAL_SETTINGS = {
   'SOME_CONST': 'thingy',
   'SOME_OTHER_CONST': 'other_thingy',
}

Suppose further you already have a dictionary with some of the variables you'd like to pass your template, perhaps passed as arguments to your view. Let's call it my_dict. Suppose you want the values in my_dict to override those in the settings.GLOBAL_SETTINGSdictionary.

进一步假设您已经有一个字典,其中包含一些您想要传递给模板的变量,也许作为参数传递给您的视图。让我们称之为my_dict。假设您希望 my_dict 中的值覆盖settings.GLOBAL_SETTINGS字典中的值。

You might do something in your view like:

您可能会在您看来执行以下操作:

def my_view(request, *args, **kwargs)
    from django.conf import settings
    my_dict = some_kind_of_arg_parsing(*args,**kwargs)
    tmp = settings.GLOBAL_SETTINGS.copy()
    tmp.update(my_dict)
    my_dict = tmp
    render_to_response('the_template.html', my_dict, context_instance=RequestContext(request))

This lets you have the settings determined globally, available to your templates, and doesn't require you to manually type out each of them.

这使您可以全局确定设置,可用于您的模板,并且不需要您手动输入每个设置。

If you don'thave any additional variables to pass the template, nor any need to override, you can just do:

如果你没有任何额外的变量来传递模板,也不需要覆盖,你可以这样做:

render_to_response('the_template.html', settings.GLOBAL_SETTINGS, context_instance=RequestContext(request))

The main difference between what I'm discussing here & what Jordan has, is that for his, settings.GLOBAL_SETTINGSoverrides anything it may have in common w/ your context dictionary, and with mine, my context dictionary overrides settings.GLOBAL_SETTINGS. YMMV.

我在这里讨论的内容与 Jordan 所拥有的内容之间的主要区别在于,对于他来说,settings.GLOBAL_SETTINGS覆盖与您的上下文字典可能具有的任何共同点,而对于我,我的上下文字典覆盖settings.GLOBAL_SETTINGS. 天啊。

回答by Alan Illing

Context processors are better suited at handling more dynamic object data--they're defined as a mapping in the documentationand in many of the posts here they're being modified or passed around to views--it doesn't make sense that a template may lose access to global information because, for example, your forgot to use a specialized context processor in the view. The data is global by definition & that couples the view to the template.

上下文处理器更适合处理更动态的对象数据——它们在文档和许多帖子中被定义为映射,它们被修改或传递给视图——没有意义模板可能无法访问全局信息,例如,您忘记在视图中使用专门的上下文处理器。根据定义,数据是全局的,并且将视图与模板耦合。

A better way is to define a custom template tag. This way:

更好的方法是定义自定义模板标签。这边走:

  • templates aren't relying on views to have global information passed into them
  • it's DRY-er: the app defining the global settings can be exported to many projects, eliminating common code across projects
  • templates decide whether they have access to the global information, not the view functions
  • 模板不依赖视图来传递全局信息
  • 它是 DRY-er:定义全局设置的应用程序可以导出到许多项目,从而消除跨项目的通用代码
  • 模板决定它们是否可以访问全局信息,而不是视图函数

In the example below I deal with your problem--loading in this MIN_TIME_TEST variable--and a problem I commonly face, loading in URLs that change when my environment changes.

在下面的示例中,我将处理您的问题——加载这个 MIN_TIME_TEST 变量——以及我经常面临的一个问题,即加载随着我的环境改变而改变的 URL。

I have 4 environments--2 dev and 2 production:

我有 4 个环境——2 个开发环境和 2 个生产环境:

  • Dev: django-web server, url: localhost:8000
  • Dev: apache web server: url: sandbox.com -> resolves to 127.0.0.1
  • Prod sandbox server, url: sandbox.domain.com
  • Prod server: url: domain.com
  • 开发:django-web 服务器,url:本地主机:8000
  • 开发:apache web 服务器:url:sandbox.com -> 解析为 127.0.0.1
  • Prod 沙盒服务器,网址:sandbox.domain.com
  • 产品服务器:网址:domain.com

I do this on all my projects & keep all the urls in a file, global_settings.py so it's accessible from code. I define a custom template tag {% site_url %} that can be (optionally) loaded into any template

我在我的所有项目中都这样做,并将所有 url 保存在一个文件 global_settings.py 中,以便可以从代码中访问它。我定义了一个自定义模板标签 {% site_url %} 可以(可选)加载到任何模板中

I create an app called global_settings, and make sure it's included in my settings.INSTALLED_APPS tuple.

我创建了一个名为 global_settings 的应用程序,并确保它包含在我的 settings.INSTALLED_APPS 元组中。

Django compiles templated text into nodes with a render() method that tells how the data should be displayed--I created an object that renders data by returnning values in my global_settings.py based on the name passed in.

Django 使用 render() 方法将模板化文本编译为节点,该方法告诉如何显示数据——我创建了一个对象,该对象通过根据传入的名称返回 global_settings.py 中的值来呈现数据。

It looks like this:

它看起来像这样:

from django import template
import global_settings

class GlobalSettingNode(template.Node):
    def __init__(self, settingname):
        self.settingname = settingname;
    def render(self, context):
        if hasattr(global_settings, self.settingname):
            return getattr(global_settings, self.settingname)
        else:
            raise template.TemplateSyntaxError('%s tag does not exist' % self.settingname)

Now, in global_settings.py I register a couple tags: site_url for my example and min_test_time for your example. This way, when {% min_time_test %} is invoked from a template, it'll call get_min_time_test which resolves to load in the value=5. In my example, {% site_url %} will do a name-based lookup so that I can keep all 4 URLs defined at once and choose which environment I'm using. This is more flexible for me than just using Django's built in settings.Debug=True/False flag.

现在,在 global_settings.py 中,我注册了几个标签:site_url 用于我的示例,而 min_test_time 用于您的示例。这样,当从模板调用 {% min_time_test %} 时,它会调用 get_min_time_test,它解析为加载 value=5。在我的示例中,{% site_url %} 将执行基于名称的查找,以便我可以同时定义所有 4 个 URL 并选择我正在使用的环境。这对我来说比仅使用 Django 的内置 settings.Debug=True/False 标志更灵活。

from django import template
from templatenodes import GlobalSettingNode
register = template.Library()


MIN_TIME_TEST = 5

DEV_DJANGO_SITE_URL = 'http://localhost:8000/'
DEV_APACHE_SITE_URL = 'http://sandbox.com/'
PROD_SANDBOX_URL = 'http://sandbox.domain.com/'
PROD_URL = 'http://domain.com/'

CURRENT_ENVIRONMENT = 'DEV_DJANGO_SITE_URL'



def get_site_url(parser, token):
    return GlobalSettingNode(CURRENT_ENVIRONMENT)

def get_min_time_test(parser, token):
    return GlobalSettingNode('MIN_TIME_TEST')

register.tag('site_url', get_site_url)
register.tag('min_time_test', get_min_time_test)

Note that for this to work, django is expecting global_settings.py to be located in a python packaged called templatetags under your Django app. My Django app here is called global_settings, so my directory structure looks like:

请注意,为此,django 希望 global_settings.py 位于 Django 应用程序下名为 templatetags 的 Python 打包中。我的 Django 应用程序在这里称为 global_settings,所以我的目录结构如下所示:

/project-name/global_settings/templatetags/global_settings.py etc.

/project-name/global_settings/templatetags/global_settings.py 等

Finally the template chooses whether to load in global settings or not, which is beneficial for performance. Add this line to your template to expose all the tags registered in global_settings.py:

最后模板选择是否在全局设置中加载,这有利于性能。将此行添加到您的模板以公开在 global_settings.py 中注册的所有标签:

{% load global_settings %}

Now, other projects that need MIN_TIME_TEST or these environments exposed can simply install this app =)

现在,其他需要 MIN_TIME_TEST 或暴露这些环境的项目可以简单地安装这个应用程序 =)