我想在Django项目中有一些常量。例如,假设一个名为MIN_TIME_TEST
的常量。
我希望能够在两个地方访问此常量:从我的Python代码中,以及在任何模板中。
这样做最好的方法是什么?
修改 为了澄清,我知道模板上下文处理器以及只是将东西放在settings.py或其他文件中而只是导入。
我的问题是,如何在不违反“不要重复自己”规则的情况下结合这两种方法?基于到目前为止的答案,这是我的方法:
我想创建一个名为global_constants.py的文件,它有一个常量列表(像MIN_TIME_TEST = 5
这样的东西)。我可以import
将此文件放入任何模块中以获取常量。
但是现在,我想创建返回所有这些常量的上下文处理器。我怎样才能自动执行此操作,而无需在字典中再次列出它们,例如John Mee的答案?
答案 0 :(得分:17)
Luper和Vladimir都是正确的,但你需要两者才能完成你的要求。
虽然常量 不在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,
}
但如果你是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)
答案 1 :(得分:6)
基于其他人的答案,这里有一个简单的方法来实现这个:
在您的设置文件中:
GLOBAL_SETTINGS = {
'MIN_TIME_TEST': 'blah',
'RANDOM_GLOBAL_VAR': 'blah',
}
然后,建立John Mee's context processor:
def settings(request):
"""
Put selected settings variables into the default template context
"""
from django.conf import settings
return settings.GLOBAL_SETTINGS
这将解决DRY问题。
或者,如果您只打算偶尔使用全局设置并想要在视图中调用它们:
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
答案 2 :(得分:3)
考虑将其放入应用程序的settings.py中。当然,为了在模板中使用它,您需要将其作为任何其他常用变量提供给模板。
答案 3 :(得分:2)
使用context processors让你的常量在所有模板中都可用(settings.py是一个定义它们的好地方,如弗拉基米尔所说)。
答案 4 :(得分:1)
上下文处理器更适合处理更多动态对象数据 - 它们被定义为documentation中的映射,并且在这里的许多帖子中它们被修改或传递给视图 - 它模板可能无法访问全局信息是没有意义的,例如,您忘记在视图中使用专门的上下文处理器。根据定义,数据是全球性的。将视图耦合到模板。
更好的方法是定义自定义模板标记。这样:
在下面的示例中,我处理您的问题 - 加载此MIN_TIME_TEST变量 - 以及我经常遇到的问题,加载在我的环境发生变化时更改的网址。
我有4个环境--2个开发和2个生产:
我在所有项目中执行此操作&将所有url保存在一个文件global_settings.py中,以便可以从代码中访问它。我定义了一个自定义模板标记{%site_url%},可以(可选)加载到任何模板
中我创建了一个名为global_settings的应用程序,并确保它包含在我的settings.INSTALLED_APPS元组中。
Django使用render()方法将模板化文本编译成节点,该方法告诉数据应该如何显示 - 我创建了一个对象,通过在我的global_settings.py中根据传入的名称返回值来呈现数据。
看起来像这样:
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)
现在,在global_settings.py中我注册了几个标签:site_url代表我的例子,min_test_time代表你的例子。这样,当从模板调用{%min_time_test%}时,它将调用get_min_time_test,该值解析为加载值= 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)
请注意,为了实现这一点,django希望global_settings.py位于Django应用程序下名为templatetags的python包中。我的Django应用程序名为global_settings,因此我的目录结构如下:
/project-name/global_settings/templatetags/global_settings.py 等
最后,模板选择是否加载全局设置,这有利于提高性能。将此行添加到模板中以显示在global_settings.py中注册的所有标记:
{% load global_settings %}
现在,需要MIN_TIME_TEST或暴露这些环境的其他项目可以简单地安装此应用程序=)
答案 5 :(得分:0)
在上下文处理器中,您可以使用以下内容:
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)
答案 6 :(得分:0)
John Mee最后一部分的变体,对Jordan Reiter讨论的相同想法进行了一些阐述。
假设您的设置中有类似于Jordan建议的内容 - 换句话说,就像:
GLOBAL_SETTINGS = {
'SOME_CONST': 'thingy',
'SOME_OTHER_CONST': 'other_thingy',
}
假设您已经有一个字典,其中包含您想要传递模板的一些变量,可能会作为参数传递给您的视图。我们称之为my_dict
。假设您希望my_dict中的值覆盖settings.GLOBAL_SETTINGS
字典中的值。
您可以在视图中执行以下操作:
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))
这使您可以全局确定设置,模板可以使用,并且不需要您手动输入每个设置。
如果您没有有任何其他变量来传递模板,也不需要覆盖,您可以这样做:
render_to_response('the_template.html', settings.GLOBAL_SETTINGS, context_instance=RequestContext(request))
我在这里讨论的主要区别与Jordan有什么,是因为他的settings.GLOBAL_SETTINGS
覆盖了它与你的上下文词典可能有的共同点,而我的上下文词典会覆盖settings.GLOBAL_SETTINGS
。 YMMV。