Определение констант в Django
Я хочу иметь некоторые константы в проектах Django. Например, предположим, что константа называется MIN_TIME_TEST
.
Я хотел бы иметь доступ к этой константе в двух местах: изнутри моего кода Python и из любых шаблонов.
Какой лучший способ сделать это?
EDIT:
Чтобы уточнить, я знаю о Template Context Processors и о том, как просто вставлять вещи в settings.py или какой-либо другой файл и просто импортировать.
Мой вопрос: как мне объединить два подхода, не нарушая правило "Не повторяй себя"? Основываясь на ответах до сих пор, здесь мой подход:
Я хотел бы создать файл global_constants.py, который будет иметь список констант (например, MIN_TIME_TEST = 5
). Я могу import
этот файл в любой модуль получить константы.
Но теперь я хочу создать обработчик контекста, который возвращает все эти константы. Как я могу сделать это автоматически, не переписывая их снова в словаре, как в ответ на John Mee?
Ответы
Ответ 1
Оба Luper и Vladimir являются правильными imho, но вам понадобятся оба, чтобы выполнить ваши требования.
-
Хотя константы не обязательно должны быть в settings.py, вы можете поместить их в любом месте и импортировать их из этого места в свой код view/model/module. Иногда я помещаю их в __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)
Ответ 2
Чтобы опираться на ответы других людей, здесь вы можете просто реализовать это:
В вашем файле настроек:
GLOBAL_SETTINGS = {
'MIN_TIME_TEST': 'blah',
'RANDOM_GLOBAL_VAR': 'blah',
}
Затем, построив обработчик контекста John Mee:
def settings(request):
"""
Put selected settings variables into the default template context
"""
from django.conf import settings
return settings.GLOBAL_SETTINGS
Это решит проблему СУХОЙ.
Или, если вы планируете иногда использовать глобальные настройки и хотите вызвать их из представления:
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
Ответ 3
Подумайте о том, чтобы поместить его в settings.py вашего приложения. Конечно, чтобы использовать его в шаблоне, вам нужно сделать его доступным для шаблона как любую другую обычную переменную.
Ответ 4
Используйте контекстные процессоры, чтобы ваши константы были доступны во всех шаблонах (settings.py - отличное место для определения их, как сказал Владимир).
Ответ 5
Контекстные процессоры лучше подходят для обработки более динамических данных объекта - они определены как сопоставление в документации и во многих здесь они изменяются или передаются в представлениях - не имеет смысла, что шаблон может потерять доступ к глобальной информации, потому что, например, вы забыли использовать специализированный процессор контекста в представлении. Данные глобальны по определению и сопоставляют представление с шаблоном.
Лучше всего определить собственный тег шаблона. Таким образом:
- шаблоны не полагаются на представления, чтобы иметь в них глобальную информацию.
- это DRY-er: приложение, определяющее глобальные параметры, может быть экспортировано во многие проекты, исключая общий код для проектов
- шаблоны решают, имеют ли они доступ к глобальной информации, а не функции просмотра
В приведенном ниже примере я расскажу о вашей проблеме - загрузке в этой переменной MIN_TIME_TEST и о проблеме, с которой я обычно сталкиваюсь, при загрузке в URL-адресах, которые меняются при изменении моей среды.
У меня 4 среды - 2 dev и 2:
- Dev: django-web server, url: localhost: 8000
- Dev: веб-сервер apache: url: sandbox.com → разрешает 127.0.0.1
- Prod sandbox server, url: sandbox.domain.com
- Сервер Prod: url: domain.com
Я делаю это во всех своих проектах и сохраняю все URL-адреса в файле global_settings.py, чтобы он был доступен из кода. Я определяю собственный шаблонный тег {% site_url%}, который может быть (необязательно) загружен в любой шаблон
Я создаю приложение под названием global_settings и удостоверяюсь, что оно включено в мои настройки. INSTALLED_APPS tuple.
Django компилирует шаблонный текст в узлы с помощью метода render(), который указывает, как должны отображаться данные. Я создал объект, который отображает данные, возвращая значения в my 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, который разрешает загружать 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)
Обратите внимание, что для этого, django ожидает, что global_settings.py будет находиться в пакете python, который называется templatetags в вашем приложении Django. Мое приложение Django называется global_settings, поэтому моя структура каталогов выглядит так:
/project-name/global_settings/templatetags/global_settings.py
и др.
Наконец, шаблон выбирает, загружать ли глобальные настройки или нет, что выгодно для производительности. Добавьте эту строку в шаблон, чтобы открыть все теги, зарегистрированные в файле global_settings.py:
{% load global_settings %}
Теперь, другие проекты, которым требуется MIN_TIME_TEST или открытые среды, могут просто установить это приложение =)
Ответ 6
В обработчике контекста вы можете использовать что-то вроде:
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)
Ответ 7
Вариант последней части Джона Ми, с небольшим уточнением по той же идее, о которой говорит Джордан Рейтер.
Предположим, что у вас есть что-то в ваших настройках, похожих на то, что предложил Джордан - другими словами, что-то вроде:
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))
Основное различие между тем, что я здесь обсуждаю, и тем, что имеет Джордан, заключается в том, что для него settings.GLOBAL_SETTINGS
переопределяет все, что может иметь общий словарь/контекстный словарь, а мой мой словарь переключает settings.GLOBAL_SETTINGS
, YMMV.