Package: django-pkgconf
Yet another application settings helper.RationaleIt’s a common practice to put a settings file in a distribution package with some predefined stuff which can be overridden later in global project’s settings.
But there is also a good reason to separate all your settings within your apps just like you do so with common python code: models, views, etc.
That’s not a big thing if your project doesn’t come with dozen apps, but if it does, flushing out non-project stuff is a good way to not mess things around and keep them way simple.QuickstartLets say you have an email service application in your project dir and it stores some configuration insettings.py:MYEMAILSERVICE_USERNAME='username'MYEMAILSERVICE_PASSWORD='password'...It’s a big temptation to write shortUSERNAME, but you have to use prefixes to prevent conflicts with other application settings and tell collaboratorsthis is for the email app. And then:# emails/foo.pyfromdjango.confimportsettings.service=Service(username=settings.MYEMAILSERVICE_USERNAME,password=settings.MYEMAILSERVICE_PASSWORD,...)Prefixes are everywhere. You always have to sayMYEMAILSERVICE_in every single place you need to access the settings. How about this one:# Package settings in emails/conf.pyfrompkgconfimportConfclassMyEmailService(Conf):USERNAME='username'PASSWORD='password'@propertydefDEBUG(self):returnself.USERNAME.startswith('test_')There is nothing more to say:# emails/foo.py# Note: your MyEmailService class becomes a module,# you import it directlyfrom.importconfservice=Service(username=conf.USERNAME,password=conf.PASSWORD,...)django-pkgconfwraps your application settings and provides a handy shortcut.But what about test or dev settings? Just define them like you always do (configuration class name becomes a prefix).Old style:# local_settings.pyMYEMAILSERVICE_USERNAME='test_username'Cool style (django-configurationsway):# settings.pyclassProd(Configuration):# No email service settings at allpassclassTest(Prod):MYEMAILSERVICE_USERNAME='test_username'It looks for the required setting in django’s configuration file first and returns original value if it’s not overridden:# emails/foo.pyfrom.importconfconf.USERNAME# 'test_username'conf.PASSWORD# 'password' - returns original valueconf.DEBUG# TrueSince0.3.0mixins are supported:frompkgconfimportConfclassFacebookMixin:FACEBOOK_APP_ID='foo'FACEBOOK_SECRET='bar'classTwitterMixin:TWITTER_APP_ID='foo'TWITTER_SECRET='bar'classInstagramMixin:INSTAGRAM_APP_ID='foo'INSTAGRAM_SECRET='bar'classSocialAppConf(FacebookMixin,TwitterMixin,InstagramMixin,Conf):DEBUG=TrueInstallationInstall the package:pip install -U django-pkgconfRead thequickstart.CompatabilityTested on py 3.5, 3.6, 3.7, 3.8 with django 1.11, 2.2, 3.0.Powered siblingsThere are more advanced apps with (probably) some extra (better?) options:django-appsettings,django-appconf, etc. The reason I’ve published this one is those apps are too big and tricky to do this little work, so you might prefer them instead.LimitationsDue to the code simplicity,propertydescriptor is used togetdata from the settings. That means you can notset(orchange) configuration valuesin action. I don’t know why you would do that, but I have to warn you.Since your app’s settings are defined in separate file, they are not accessible viadjango.conf.settings(until you override them in your project settings). This application doesn’t create backward compatibility links. You should always use package configuration module.Changelogv0.4.0Python 3 onlyv0.3.0Added mixins support.v0.2.1 - 0.2.2Addedimport *support.__prefix__is generated automatically if not presented in class.
That may help to build graceful exceptions like'foo_value' was not found in MYAPP_FOO_SETTING.v0.2.0Added__prefix__attribute to support prefix-names with underscores.Added instance method and property support.Backward incompatible change:functions must haveselfas the first argument now.v0.1.0First public release