What's a djangonautic way of handling default settings in an app if one isn't defined in settings.py
?
I've currently placed a default_settings
file in the app and I've considered a few options. I'm leaning towards the first option, but there may be pitfalls I'm not aware of in using globals()
I've mostly seen apps do a FOO = getattr(settings, 'FOO', False)
at the top of the file that uses the setting but I think there are readability/repetition problems with this approach if the values / names are long.
1: Place settings in a function and iterate over locals / set globals
def setup_defaults(): FOO = 'bar' for key, value in locals().items(): globals()[key] = getattr(settings, key, value) setup_defaults()
Pros:
Cons:
2: Write getattr(settings, 'MY_SETTING', default_settings.MY_SETTING)
every call
Pros: - Very clear.
Cons: - Repetitive
3: Always define settings as FOO = getattr(settings, 'FOO', '...setting here...')
Pros: - Defaults are always overridden
Cons:
4: Create utility function to get_or_default(setting)
Pros:
Cons:
5: Create a settings class
class Settings(object): FOO = 'bar' def __init__(self): # filter out the startswith('__') of # self.__dict__.items() / compare to django.conf.settings? my_settings = Settings()
Cons:
I'd love to hear feedback.
I think it's quite common to create a settings.py
in your app's package, where you define your settings like this:
from django.conf import settings FOO = getattr(settings, 'FOO', "default_value")
In your app you can import them from your app's settings
module:
from myapp.settings import * def print_foo(): print FOO
But I think everybody agrees that Django is lacking a better generic architecture for this! If you're looking for a more sophisticated way to handle this, there are some third party apps for this like django-appconf, but it's your decision if you want to introduce one more dependency for your app or not!
In settings.py
, put settings.*
before the property.
from django.conf import settings settings.FOO = getattr(settings, 'FOO', "default_value")
It seems that every solution I see there tends to create an internal copy of application settings, proxy, wrap or whatever. This is confusing and creates problems when settings are modified in run time like they do in tests.
To me all settings belong in django.conf.settings
and only there. You should not read them from somewhere else nor copy it for later use (as they may change). You should set them once and don't bother about defaults later on.
I understand the impulse to drop the app prefix when app setting is used internally, but this also is IMHO a bad idea. When in trouble looking for SOME_APP_FOO
will not yield results, as it's used just as FOO
internally. Confusing right? And for what, few letters? Remember that explicit is better?
IMHO the best way is to just set those defaults in Django's own settings, and why don't use piping that is already there? No module import hooks or hijacking models.py
being always imported to initialize some extra and complicated meta class piping.
Why not use AppConfig.ready for setting defaults?
class FooBarConfig(AppConfig): name = 'foo_bar' def ready(self): from django.conf import settings settings = settings._wrapped.__dict__ settings.setdefault('FOO_BAR_SETTING', 'whatever')
Or better yet define them in clean simple way in a separate module and import them as (or close to how) Settings class does it:
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))
I'm not sure use of __dict__
is the best solution, but you get the idea, you can always user hasattr
/setattr
combo to get the efect.
This way your app settings are:
django.conf.settings
— you can implement some transposition of names if you want toPS. There is a warning about not modifying settings in run time but it does not explain why. So I think this one time, during initialization may be a reasonable exception ;)
PS2. Don't name the separate module just settings
as this may get confusing when you import settings
from django.conf
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With