Подтвердить что ты не робот

Стандарт по умолчанию для Django для подключаемого приложения?

Какой djangonautic способ обработки настроек по умолчанию в приложении, если он не определен в settings.py?

В настоящее время я разместил файл default_settings в приложении, и я рассмотрел несколько вариантов. Я склоняюсь к первому варианту, но могут быть подводные камни, о которых я не знаю при использовании globals()

В основном я видел, что приложения используют FOO = getattr(settings, 'FOO', False) в верхней части файла, который использует этот параметр, но я думаю, что есть проблемы чтения/повторения с этим подходом, если значения/имена длинны.


1: Поместите настройки в функцию и итерации по locals/set globals

def setup_defaults():
    FOO = 'bar'
    for key, value in locals().items():
        globals()[key] = getattr(settings, key, value)

setup_defaults()

Плюсы:

  • Нужно только написать имя var однажды, чтобы вытащить значение по умолчанию с тем же именем из настроек django.

Минусы:

  • Не используется для использования globals() и не знает о каких-либо последствиях

2: Напишите getattr(settings, 'MY_SETTING', default_settings.MY_SETTING) каждый вызов

Плюсы: - Очень ясно.

Минусы: - Повторяющийся


3: Всегда задавайте настройки как FOO = getattr(settings, 'FOO', '...setting here...')

Плюсы: - значения по умолчанию всегда переопределены.

Минусы:

  • Повторяющийся (должен определять var дважды - один раз в форме строки, один раз в var)
  • Настройка не так читаема, так как теперь это третий аргумент

4: создать функцию утилиты get_or_default(setting)

Плюсы:

  • Простой
  • Не нужно повторять строковое представление настроек

Минусы:

  • Нужно называть его

5: создать класс настроек

class Settings(object):
    FOO = 'bar'

    def __init__(self):
         # filter out the startswith('__') of 
         # self.__dict__.items() / compare to django.conf.settings?

my_settings = Settings()

Минусы:

  • Невозможно сделать из foo.bar.my_settings import FOO (на самом деле, это ужасный разбойник!)

Я хотел бы услышать отзывы.

4b9b3361

Ответ 1

Я думаю, что довольно просто создать settings.py в вашем приложении, где вы определяете свои настройки следующим образом:

from django.conf import settings
FOO = getattr(settings, 'FOO', "default_value")

В вашем приложении вы можете импортировать их из своего модуля приложения settings:

from myapp.settings import *

def print_foo():
    print FOO

Но я думаю, все согласны с тем, что для Django нет лучшей общей архитектуры! Если вы ищете более сложный способ справиться с этим, есть некоторые сторонние приложения для этого, например django-appconf, но это ваше решение если вы хотите ввести еще одну зависимость для своего приложения или нет!

Ответ 2

Как насчет этого?

В myapp/settings.py:

from django.conf import settings

FOO = 'bar'
BAR = 'baz'

_g = globals()
for key, value in _g.items():
    _g[key] = getattr(settings, key, value)

В myapp/other.py:

import myapp.settings

print myapp.settings.FOO

Учитывая этот ответ от ncoghlan, я уверен, что использую globals() таким образом.

Ответ 3

В ответ на Phil Gyford comment, подвергая проблему настройкам, не перезаписываемым в тестах (поскольку уже импортировано в модули), я сделал, чтобы определить AppSettings класс в __init__.py с помощью:

  • a __init__ для инициализации каждой настройки до None
  • a load метод загрузки всех настроек из геттеров
  • статические геттеры для каждой настройки

Затем в коде:

from . import AppSettings

def in_some_function():
    some_setting = AppSettings.get_some_setting()

Или если вы хотите загрузить их все за один раз (но переопределяющие настройки в тестах не будут работать для затронутого модуля):

from . import AppSettings

app_settings = AppSettings()
app_settings.load()

def in_some_function():
   print(app_settings.some_setting)

Затем вы можете использовать декоратор override_settings в своих тестах и ​​по-прежнему иметь некоторый СУХОЙ и понятный способ использования настроек приложения за счет большего количества инструкций, выполняемых каждый раз, когда вы хотите получить настройку (только для тестов...).

Ответ 4

Кажется, что каждое решение, которое я вижу там, имеет тенденцию создавать внутреннюю копию настроек приложения, прокси, перенос или что-то еще. Это запутывает и создает проблемы, когда параметры изменяются во время выполнения, как в тестах.

Для меня все настройки принадлежат django.conf.settings и только там. Вы не должны читать их из другого места и не копировать их для последующего использования (поскольку они могут измениться). Вы должны установить их один раз и не беспокоиться о дефолтах позже.

Я понимаю импульс для удаления префикса приложения, когда настройка приложения используется внутри, но это также ИМХО - плохая идея. Когда при поиске SOME_APP_FOO не будут получены результаты, так как он используется как FOO внутренне. Сбивать с толку? И для чего, несколько писем? Помните что явное лучше?

ИМХО лучший способ - просто установить эти значения по умолчанию в собственных настройках Django и почему не использовать трубопровод, который уже существует? Никакие блокировки импорта или захват модуля models.py не всегда импортируются, чтобы инициализировать некоторые дополнительные и сложные метаклассы.

Почему бы не использовать AppConfig.ready для установки значений по умолчанию?

class FooBarConfig(AppConfig):
    name = 'foo_bar'

    def ready(self):
        from django.conf import settings
        settings = settings._wrapped.__dict__
        settings.setdefault('FOO_BAR_SETTING', 'whatever')

Или еще лучше определить их простым способом в отдельном модуле и импортировать их как (или близко к ним) класс настроек

class FooBarConfig(AppConfig):
    name = 'foo_bar'

    def ready(self):
        from . import app_settings as defaults
        from django.conf import settings
        for name in dir(defaults):
            if name.isupper() and not hasattr(settings, name):
                setattr(settings, name, getattr(defaults, name))

Я не уверен, что использование __dict__ - лучшее решение, но вы поняли, что вы всегда можете использовать user hasattr/setattr, чтобы получить efect.

Таким образом, ваши настройки приложения:

  • для других - если они должны полагаться на них в некоторых редких случаях, если, конечно, приложения настроены для того, чтобы полагаться друг на друга
  • обычно читается как любой другой параметр
  • красиво объявлено в своем собственном модуле
  • достаточно ленивый
  • контролируется, как они установлены в django.conf.settings - вы можете реализовать некоторую транспозицию имен, если вы хотите

PS. Существует предупреждение о том, что вы не изменяете настройки во время выполнения, но это не объясняет почему. Поэтому я думаю, что это один раз, во время инициализации может быть разумным исключением;)

PS2. Не называйте отдельный модуль только settings, так как это может запутаться при импорте settings из django.conf.

Ответ 5

Номер 3 лучше, потому что он самый простой. И очень последовательный взгляд.

Номер 1: его легко упустить. Если я открою ваш код, и я не прокручу его до конца, я пропущу его, и я подумаю, что настройки не могут быть переопределены в моем собственном модуле.

Номер 2: не только повторяется, его труднее читать, потому что он слишком длинный, и значения по умолчанию будут определены несколько раз и будут разбросаны по всему вашему коду.

Число 4: непоследовательные, повторяющиеся вызовы.

Номер 5: Не согласующийся, мы ожидаем, что настройки будут определены в модуле, не входящем в класс. Ну, по крайней мере, я ожидаю, что это будет определено как модуль, потому что я видел множество приложений, использующих метод 3, и я использую его сам, чтобы я мог быть предвзятым.