Комментарии 38
Все сравнительно стандартно, в работе использую почти такой же. Но для начинающих, возможно, пригодится — сразу будут делать правильно.
НЛО прилетело и опубликовало эту надпись здесь
Настройки БД должны быть в локальном конфиге еще хотя бы и потому, что пароль от базы нехорошо держать в VCS.
Да и базы (dev/production) должны быть разными. А какие «инциденты» могут быть, не понимаю?
Да и базы (dev/production) должны быть разными. А какие «инциденты» могут быть, не понимаю?
за django-command-extensions отдельное спасибо, буду копать ))
Почему не написать «DEBUG = True» в локальном конфиге dev-сервера и не хардкодить имя домена?
Кстати, как бы попроще включать режим отладки для определенных ip?
Знаю, что есть решения через middleware, но они мне показались странными…
Кстати, как бы попроще включать режим отладки для определенных ip?
Знаю, что есть решения через middleware, но они мне показались странными…
Подому как автор подключает локальный конфиг в конце. Мне кажется подключение локального конфига в начале — практичнее, так как позволяет в основном конфиге использовать разичные настройки из локального.
Ах… Ну я тоже за подключение локального конфига в начале. И в try не оборачивать.
Разве практичнее? Ведь в этом случае глобальные настройки будут перекрывать глобальные. По-моему, должно быть с точностью, да наоборот: в глобальном конфиге только то, что не зависит от платформы, а в локальном уже делать переопределения.
Ведь в этом случае глобальные настройки будут перекрыватьглобальныелокальные
Предыдущий комментарий надо читать вот так
А зачем вы одни и те же настройки пишите и как локальные, и как глобальные? Для того, чтобы локально можно было переопределить любую глобальную настройку? В тех случаях, с которыми я сталкивался — всюду можно было определить, какие настройки будут общими для всех, а какие — будут заданы локально.
Вместо того, чтобы оставлять в общем конфиге невразумительное
Вместо того, чтобы оставлять в общем конфиге невразумительное
DATABASE_ENGINE = ''не лучше ли написать что-то вроде
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
import env(здесь evn — импортированный вначале файл с конфигурацией окружения). В такой форме сразу видно, что даная опция вовсе не оставлена пустой, а задана локально.
DATABASE_ENGINE = 'django.db.backends.postgresql_psycopg2'
DATABASE_NAME = env.DATABASE_NAME
DATABASE_USER = env.DATABASE_USER
DATABASE_PASSWORD = env.DATABASE_PASSWORD
DATABASE_HOST = env.DATABASE_HOST
DATABASE_PORT = env.DATABASE_PORT
А зачем вы одни и те же настройки пишите и как локальные, и как глобальные? Для того, чтобы локально можно было переопределить любую глобальную настройку?
Почти. Для того, чтобы в случае надобности можно было переопределить любую глобальную настройку. А когда надобности нет, не писать ни одной лишней строчки :-)
Попробую проиллюстрировать на примере. Я обычно прописываю в settings что-то такое:
DEBUG=False
TEMPLATE_LOADERS = (
('django.template.loaders.cached.Loader',
(
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
),
)
# ...etc
То есть по умолчанию отладочный режим выключен, а кеширование шаблонов включено. Для боевого сервера это годится, для девелоперской машины — не очень. Поэтому в local_settings девелоперского окружения я просто переопределяю значения так, как мне нужно:
DEBUG=True
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)
В локальных настройках продакшн-сервера я эти атрибуты не переопределяю. не лучше ли написать что-то вроде...
По-моему, не просто не лучше, а намного хуже. Хотя бы потому что эти атрибуты встречаются во всех окружениях: и в глобальном (хорошо хоть, что их менять не надо), и в каждом из локальных. Короче, не мой выбор :-)
Проблемы с вашим вариантом:
1. По основному конфигу не очевидно, что используется как есть, что будет обязательно переопределено, а что может быть переопределено.
2. В основном конфиге нет возможность делать зависимости от настроек, заданных в локальном конфиге.
3. Зная лишь глобальный конфиг нет возможности определить, как сформировать локальный конфиг. Да и вообще определить, что там может находиться.
Да, ваш вариант гибче, но он в целом менее читабелен (что противоречит правилу «Readability counts» :) и боюсь он быстро становится трудноподдерживаемым. «Короче, не мой выбор» :D
1. По основному конфигу не очевидно, что используется как есть, что будет обязательно переопределено, а что может быть переопределено.
2. В основном конфиге нет возможность делать зависимости от настроек, заданных в локальном конфиге.
3. Зная лишь глобальный конфиг нет возможности определить, как сформировать локальный конфиг. Да и вообще определить, что там может находиться.
Да, ваш вариант гибче, но он в целом менее читабелен (что противоречит правилу «Readability counts» :) и боюсь он быстро становится трудноподдерживаемым. «Короче, не мой выбор» :D
Всё, что вы описали — не проблемы, а решения, к которым долго и сознательно шли :)
В репозиторий мы помещаем шаблон локального конфига —
Поможете? :-)
Или я его неправильно понял?
1. По основному конфигу не очевидно, что используется как есть, что будет обязательно переопределено, а что может быть переопределено.У нас действует соглашение, по которому глобальный конфиг является полностью рабочим. Единственное исключение — атрибут DATABASES, который обязательно всё-таки указать вручную.
В репозиторий мы помещаем шаблон локального конфига —
settings_local.py.template
, в котором указан шаблон обязательного атрибута DATABASES. В том же файле содержатся дополнительные атрибуты, которые желательно (но не обязательно) изменить для лучшего функционирования рабочей копии.2. В основном конфиге нет возможность делать зависимости от настроек, заданных в локальном конфиге.Это не проблема, а умышленное поведение. Я почему всюду этот settings и обзываю глобальным: он ни разу не должен зависеть от окружения и везде одинаков. И я, если честно, не могу придумать адекватного случая, когда такая зависимость нужна.
Поможете? :-)
3. Зная лишь глобальный конфиг нет возможности определить, как сформировать локальный конфиг. Да и вообще определить, что там может находиться.Чем-то этот пункт напоминает п.1. Поэтому ответ тот же: настройки, которые желательно изменить, перечисляются в
local_settings.py.template
, на основе которого уже и лепится local_settings
.Или я его неправильно понял?
TEMPLATE_DIRS = ()
for root, dirs, files in os.walk(PROJECT_PATH)
if 'templates' in dirs: TEMPLATE_DIRS += (os.path.join(root, 'templates'),)
При такой схеме сложно будет объяснить вашей любимой IDE, где именно искать шаблоны.
Я делаю так:
TEMPLATE_DIRS = (
os.path.abspath(PROJECT_DIR),
os.path.abspath(PROJECT_DIR) + '/templates', # тут общие шаблоны -- base, 404, 500...
)
и пишу имена шаблонов более развернуто:
return render_to_response('geo/templates/index.html', content, RequestContext(request))
return render_to_response('geo/templates/index.html', content, RequestContext(request))Посмотрите django-annoying. Авось пригодится.
а зачем такая жуть: 'geo/templates/index.html'? Почему не просто 'geo/index.html'? Папку geo можно создать в PROJECT_ROOT/templates или в PROJECT_ROOT/geo/templates/
Я бы хотел, чтобы шаблоны приложения были внутри его директории. Бывает, что приложение достаточно независимо может работать.
или в PROJECT_ROOT/geo/templates/Это не понял. У меня же так и есть? Или предлагается создать внутри "/geo/templates/" еще папку geo только для того, чтобы сократить путь с 'geo/templates/index.html' до 'geo/index.html'? А IDE как поймет, где эти шаблоны искать?
Обратите внимание на эту штуку:
она делает ровно то, что Вы хотите. Строго говоря, чтобы шаблоны из директории приложения подхватывались, TEMPLATE_DIRS можно и не заполнять.
TEMPLATE_LOADERS = (
#...
'django.template.loaders.app_directories.load_template_source',
)
она делает ровно то, что Вы хотите. Строго говоря, чтобы шаблоны из директории приложения подхватывались, TEMPLATE_DIRS можно и не заполнять.
Да, в geo/templates/ делаем папку geo. Это полезный паттерн, и так делает большинство сторонних приложений. Чем он полезен:
а) папку с шаблонами можно безболезненно перемещать между geo/templates и PROJECT_ROOT/templates
б) в одном приложении можно задать несколько «неймспейсов» для шаблонов
в) не требуется никаких хаков (вроде вашего) для того, чтобы подключать шаблоны
г) шаблоны гарантированно (ну почти, с точностью до названия приложения) не «мусорят» и не перекрывают шаблоны других приложений. У Вас, если что, перекрывают, и это может привести (и когда-нибудь обязательно приведет) к странным багам.
Про IDE вообще не понял, если честно. Зачем IDE «искать шаблоны», что под этим подразумевается?
а) папку с шаблонами можно безболезненно перемещать между geo/templates и PROJECT_ROOT/templates
б) в одном приложении можно задать несколько «неймспейсов» для шаблонов
в) не требуется никаких хаков (вроде вашего) для того, чтобы подключать шаблоны
г) шаблоны гарантированно (ну почти, с точностью до названия приложения) не «мусорят» и не перекрывают шаблоны других приложений. У Вас, если что, перекрывают, и это может привести (и когда-нибудь обязательно приведет) к странным багам.
Про IDE вообще не понял, если честно. Зачем IDE «искать шаблоны», что под этим подразумевается?
Наверное, каждый месяц кто-нибудь у себя в блоге напишет о том, как настраивать settings.py) Думаю, число статей с советами за несколько сотен должно перевалить было уже давно.
А это зачем? Можно просто добавть os.path.join(PROJECT_ROOT, 'templates') в TEMPLATE_DIRS. Шаблоны в папках templates у приложений 'django.template.loaders.app_directories.Loader' ведь сам находит.
for root, dirs, files in os.walk(PROJECT_PATH)
if 'templates' in dirs: TEMPLATE_DIRS += (os.path.join(root, 'templates'),)
А это зачем? Можно просто добавть os.path.join(PROJECT_ROOT, 'templates') в TEMPLATE_DIRS. Шаблоны в папках templates у приложений 'django.template.loaders.app_directories.Loader' ведь сам находит.
Кошмар, код не оформлен, что критично для Python.
После такого вообще пропадает желание читать:
if socket.gethostname() == 'your.domain.com':
DEBUG = False
else:
DEBUG = True
После такого вообще пропадает желание читать:
if socket.gethostname() == 'your.domain.com':
DEBUG = False
else:
DEBUG = True
Комментарии — зло:
Вот за это я и ненавижу комментарии.
'your.domain.com' должна быть константой с именем PRODUCTION_SERVER
И весь кусок должен быть написан так:
# Set DEBUG = True if on the production server
Вот за это я и ненавижу комментарии.
'your.domain.com' должна быть константой с именем PRODUCTION_SERVER
И весь кусок должен быть написан так:
DEBUG = socket.gethostname() == PRODUCTION_SERVER
Большое спасибо за статью!
Некоторые хитрости знал, но остальные возьму на вооружение.
Пишите еще, делитесь практическим опытом.
Хотелось бы про использование Django и MongoDB почитать.
Может кто-нибудь из знающих людей здесь напишет?!
Некоторые хитрости знал, но остальные возьму на вооружение.
Пишите еще, делитесь практическим опытом.
Хотелось бы про использование Django и MongoDB почитать.
Может кто-нибудь из знающих людей здесь напишет?!
try:
from local_settings import *
except ImportError:
pass
несколько раз натыкался, когда в local_settings опечатка, или ошибка, продакшн сервер запускается с настройками по умолчанию. ИМХО, лучше как-то так сделать:
if os.path.isfile(os.path.join(PROJECT_PATH, "local_settings.py")):
from local_settings import *
в этом случае при ошибках в local_settings, вывалится исключение. И как по мне — удобнее в local_settings перекрывать настройки по умолчанию — подключаю в конце settings.py
А как по мне, лучше джанге вообще не позволять запускаться без local_settings:
Маловероятно ведь, что локальные настройки не понадобятся в принципе, согласитесь? Окружения — то, в котором ведётся разработка и боевое — чаще всего существенно различаются. С другой стороны, если в настройках есть какие-то проблемы, то мы о них узнаем ещё на этапе запуска сервера и вовремя всё исправим.
try:
from local_settings import *
except Exception, e:
import os, warnings
warnings.warn("Unable import local settings [%s]: %s" % (type(e), e))
sys.exit(1)
Маловероятно ведь, что локальные настройки не понадобятся в принципе, согласитесь? Окружения — то, в котором ведётся разработка и боевое — чаще всего существенно различаются. С другой стороны, если в настройках есть какие-то проблемы, то мы о них узнаем ещё на этапе запуска сервера и вовремя всё исправим.
По поводу локальных настроек — мне лично неудобно, что их приходится хранить локально — бывает систему переустановлю или еще что.
Я просто использую socket.gethostname() для того чтобы определить на какой машине запущен проект и, в зависимости от этого, разные настройки применяю :)
Я просто использую socket.gethostname() для того чтобы определить на какой машине запущен проект и, в зависимости от этого, разные настройки применяю :)
На мой взгляд гораздо проще и удобней пути в settings.py проставлять следующим образом:
import os
def rel(*x):
return os.path.join(os.path.abspath(os.path.dirname(__file__)), *x)
#указываем путь так:
MEDIA_ROOT = rel('media')
Всё хорошо, только вот не понятно, зачем таким образом странным шаблоны подключать.
Только вот теперь константы
DATABASE_ENGINE = ''
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
вроде как deprecated.
Лучше использовать DATABASES = {
'engine':…
…
}.
DATABASE_ENGINE = ''
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
вроде как deprecated.
Лучше использовать DATABASES = {
'engine':…
…
}.
Я все настройки по умолчанию помещаю в файл settings_default.py, а в settings.py у меня следующее:
Также у меня есть файл settings_production.py который выглядит похожим образом и при деплое переименовывается в settings.py. Ещё можно добавить файл settings_template.py со списком типичных параметров которые необходимо задавать индивидуально для каждой машины и использовать его в качестве основы для settings_production_xx.py
Это позволяет не просто переопределять значения переменных, но и модифицировать их. Ещё не забывайте что Джанго по какой-то причине импортирует файл settings.py дважды.
from settings_default import * DATABASES['default']['NAME'] = os.path.abspath(os.path.join(PROJECT_PATH, '../database.db'))
Также у меня есть файл settings_production.py который выглядит похожим образом и при деплое переименовывается в settings.py. Ещё можно добавить файл settings_template.py со списком типичных параметров которые необходимо задавать индивидуально для каждой машины и использовать его в качестве основы для settings_production_xx.py
Это позволяет не просто переопределять значения переменных, но и модифицировать их. Ещё не забывайте что Джанго по какой-то причине импортирует файл settings.py дважды.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Красивые конфиги Django