Настройки приложений Django
Tags: django
Published: 2020-09-07 09:26:04

## Вводная
Для всех последующих примеров кода предполагается, что выполнен импорт `settings`
``` python
from django.conf import settings
```
## Проблема
Если мы захотим использовать какую-то из настроек django в своём коде без упоминания его в settings.py, то проблем не возникнет.
``` python
# Обычно никто не задаёт значение для CSRF_COOKIE_AGE, 
print(settings.CSRF_COOKIE_AGE) # никаких ошибок, всё работает
```
Часто для своего приложения нужны свои настройки[^1]. Чтобы приложение не упало из-за отсутствия настроек в settings.py нужны проверки и подстановка значения по умолчанию.
[^1]: Я называю настройкой константу, которая влияет на поведение программы и значение которой можно задать в settings.py
``` python
print(getattr(settings, 'MY_APP_PARAM_1', default_value_of_param_1))
```
Выглядит как-то не очень, но если учесть, что одна и та же настройка может использоваться в нескольких местах, то код преображается в нечто такое:
``` python
# my_app/conf.py
default = {
    'MY_APP_PARAM_1': default_value_of_param_1,
    # Представьте, что здесь перечислены остальные настройки
}
def get_param_value(param_name):
    return getattr(settings, param_name, default_value_of_param_1)

# my_app/any_place.py
from .conf import get_param_value
print(get_param_value('MY_APP_PARAM_1')) # выглядит не очень, но работает
print(get_param_value('MY_APP_PARAM_L')) # IDE не помешает нам ошибиться
```
Хочется, чтобы работа с настройками была одинаковой для всех приложений, чтобы вид настройки был похож на `settings.MY_APP_PARAM_1` и чтобы работало автодополнение.
## Решение
Я не стал придумывать велосипед, а взял чужой. Подозреваю, что на просторах PyPi можно найти ещё с десяток, поэтому свой туда забрасывать не стал, хотя найти аналогичный мне там не удалось.
Скачать результат можно [на github gist](https://gist.github.com/gimntut/c1d61029e44461d7510f786557bb92c3#file-django_conf-py)
Код в основном взят из django-rest-framework, из него выкинуто всё, что мешает переиспользованию. Файлик кладётся в папку доступную для всех приложений django. У меня это папка `utils`.
Посмотрим как это работает
``` python
# my_app\settings.py
from utils.django import AppSettings

# Описание настроек приложения.
# 1. Все поля находятся в одном месте
# 2. Видны все значения по умолчанию
# 3. При желании можно добавить типизацию
class MyAppSettings(AppSettings):
    URL = ''
    USER: str = ''
    PASSWORD = ''

# Объект с инициализированными данными 
# 1. Достаточно написать "conf." в любом IDE
#    и редактор сам предложит название настройки
# 2. Все обращения приложения к настройкам должны
#    происходить через этот объект, тогда не будет риска,
#    что приложение "сломается" из-за внешних факторов
conf = MyAppSettings('MY_APP_CONF')
```
``` python
# django_project\settings.py
# ...

# Настройки Django-проекта
# 1. Могут быть заданны частично
# 2. Могут быть совсем не заданы
# 3. Могут быть заданы явно, без использования .env
MY_APP_CONF = {
    'URL': env('MY_APP_URL', default=''),
    'USER': env('MY_APP_USER', default=''),
    'PASSWORD': env('MY_APP_PASSWORD', default=''),
}
```
``` python
# my_app\using.py
from .settings import conf
# Здесь создаётся условный клиент с подключением к некому сервису
client = get_data(conf.URL, conf.USER, conf.PASSWORD)
```
На что следует обратить внимание:
1. Описание настроек приложения и значений по умолчанию делается очень просто.
2. Все настройки приложения задаются в одном словаре, т.е. не будут размазаны по коду и не нужны префиксы к каждой настройке.
3. Не нужны проверки на существование при использовании настроек. В худшем случае будет значение по умолчанию.