django-configurations/docs/patterns.rst

220 lines
5.9 KiB
ReStructuredText
Raw Normal View History

Usage patterns
==============
There are various configuration patterns that can be implemented with
django-configurations. The most common pattern is to have a base class
and various subclasses based on the environment they are supposed to be
used in, e.g. in production, staging and development.
Server specific settings
------------------------
For example, imagine you have a base setting class in your **settings.py**
file:
.. code-block:: python
from configurations import Configuration
class Base(Configuration):
TIME_ZONE = 'Europe/Berlin'
class Dev(Base):
DEBUG = True
class Prod(Base):
TIME_ZONE = 'America/New_York'
You can now set the ``DJANGO_CONFIGURATION`` environment variable to
one of the class names you've defined, e.g. on your production server
it should be ``Prod``. In Bash that would be:
.. code-block:: console
$ export DJANGO_SETTINGS_MODULE=mysite.settings
$ export DJANGO_CONFIGURATION=Prod
$ python -m manage runserver
Alternatively you can use the ``--configuration`` option when using Django
management commands along the lines of Django's default ``--settings``
command line option, e.g.
.. code-block:: console
$ python -m manage runserver --settings=mysite.settings --configuration=Prod
Docs: explicitly describe property in patterns.rst (#189) Hopefully this saves time for new users of django-configuration (like myself), who "just needed" to lazily evaluate a string inside a dictionary. This doubles as an example for `RAVEN_CONFIG` which was the whole reason I was here in the first place... The actual problem I faced was that a setting remains of type `values.Value` when nested inside a dictionary. Which results in a weird issues like this: ``` 2018-02-24T20:59:26.125208+00:00 app[web.1]: Traceback (most recent call last): 2018-02-24T20:59:26.125364+00:00 app[web.1]: self.client.http_context(self.get_http_context(environ)) 2018-02-24T20:59:26.125215+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/middleware.py", line 98, in __call__ 2018-02-24T20:59:26.125368+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 54, in <lambda> 2018-02-24T20:59:26.125482+00:00 app[web.1]: __getattr__ = lambda x, o: getattr(get_client(), o) 2018-02-24T20:59:26.125486+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 134, in get_client 2018-02-24T20:59:26.125613+00:00 app[web.1]: instance = Client(**options) 2018-02-24T20:59:26.125618+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/client.py", line 147, in __init__ 2018-02-24T20:59:26.125769+00:00 app[web.1]: Client.__init__(self, *args, **kwargs) 2018-02-24T20:59:26.125771+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 171, in __init__ 2018-02-24T20:59:26.125927+00:00 app[web.1]: self.set_dsn(dsn, transport) 2018-02-24T20:59:26.125929+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 251, in set_dsn 2018-02-24T20:59:26.126063+00:00 app[web.1]: if dsn not in self._transport_cache: 2018-02-24T20:59:26.126076+00:00 app[web.1]: TypeError: unhashable type: 'Value' ```
2018-02-27 20:43:18 +00:00
Property settings
-----------------
Use a ``property`` to allow for computed settings. This pattern can
also be used to postpone / lazy evaluate a value. E.g., useful when
nesting a Value in a dictionary and a string is required:
.. code-block:: python
Docs: explicitly describe property in patterns.rst (#189) Hopefully this saves time for new users of django-configuration (like myself), who "just needed" to lazily evaluate a string inside a dictionary. This doubles as an example for `RAVEN_CONFIG` which was the whole reason I was here in the first place... The actual problem I faced was that a setting remains of type `values.Value` when nested inside a dictionary. Which results in a weird issues like this: ``` 2018-02-24T20:59:26.125208+00:00 app[web.1]: Traceback (most recent call last): 2018-02-24T20:59:26.125364+00:00 app[web.1]: self.client.http_context(self.get_http_context(environ)) 2018-02-24T20:59:26.125215+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/middleware.py", line 98, in __call__ 2018-02-24T20:59:26.125368+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 54, in <lambda> 2018-02-24T20:59:26.125482+00:00 app[web.1]: __getattr__ = lambda x, o: getattr(get_client(), o) 2018-02-24T20:59:26.125486+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 134, in get_client 2018-02-24T20:59:26.125613+00:00 app[web.1]: instance = Client(**options) 2018-02-24T20:59:26.125618+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/client.py", line 147, in __init__ 2018-02-24T20:59:26.125769+00:00 app[web.1]: Client.__init__(self, *args, **kwargs) 2018-02-24T20:59:26.125771+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 171, in __init__ 2018-02-24T20:59:26.125927+00:00 app[web.1]: self.set_dsn(dsn, transport) 2018-02-24T20:59:26.125929+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 251, in set_dsn 2018-02-24T20:59:26.126063+00:00 app[web.1]: if dsn not in self._transport_cache: 2018-02-24T20:59:26.126076+00:00 app[web.1]: TypeError: unhashable type: 'Value' ```
2018-02-27 20:43:18 +00:00
class Prod(Configuration):
SOME_VALUE = values.Value(None, environ_prefix=None)
Docs: explicitly describe property in patterns.rst (#189) Hopefully this saves time for new users of django-configuration (like myself), who "just needed" to lazily evaluate a string inside a dictionary. This doubles as an example for `RAVEN_CONFIG` which was the whole reason I was here in the first place... The actual problem I faced was that a setting remains of type `values.Value` when nested inside a dictionary. Which results in a weird issues like this: ``` 2018-02-24T20:59:26.125208+00:00 app[web.1]: Traceback (most recent call last): 2018-02-24T20:59:26.125364+00:00 app[web.1]: self.client.http_context(self.get_http_context(environ)) 2018-02-24T20:59:26.125215+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/middleware.py", line 98, in __call__ 2018-02-24T20:59:26.125368+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 54, in <lambda> 2018-02-24T20:59:26.125482+00:00 app[web.1]: __getattr__ = lambda x, o: getattr(get_client(), o) 2018-02-24T20:59:26.125486+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 134, in get_client 2018-02-24T20:59:26.125613+00:00 app[web.1]: instance = Client(**options) 2018-02-24T20:59:26.125618+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/client.py", line 147, in __init__ 2018-02-24T20:59:26.125769+00:00 app[web.1]: Client.__init__(self, *args, **kwargs) 2018-02-24T20:59:26.125771+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 171, in __init__ 2018-02-24T20:59:26.125927+00:00 app[web.1]: self.set_dsn(dsn, transport) 2018-02-24T20:59:26.125929+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 251, in set_dsn 2018-02-24T20:59:26.126063+00:00 app[web.1]: if dsn not in self._transport_cache: 2018-02-24T20:59:26.126076+00:00 app[web.1]: TypeError: unhashable type: 'Value' ```
2018-02-27 20:43:18 +00:00
@property
def SOME_CONFIG(self):
Docs: explicitly describe property in patterns.rst (#189) Hopefully this saves time for new users of django-configuration (like myself), who "just needed" to lazily evaluate a string inside a dictionary. This doubles as an example for `RAVEN_CONFIG` which was the whole reason I was here in the first place... The actual problem I faced was that a setting remains of type `values.Value` when nested inside a dictionary. Which results in a weird issues like this: ``` 2018-02-24T20:59:26.125208+00:00 app[web.1]: Traceback (most recent call last): 2018-02-24T20:59:26.125364+00:00 app[web.1]: self.client.http_context(self.get_http_context(environ)) 2018-02-24T20:59:26.125215+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/middleware.py", line 98, in __call__ 2018-02-24T20:59:26.125368+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 54, in <lambda> 2018-02-24T20:59:26.125482+00:00 app[web.1]: __getattr__ = lambda x, o: getattr(get_client(), o) 2018-02-24T20:59:26.125486+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 134, in get_client 2018-02-24T20:59:26.125613+00:00 app[web.1]: instance = Client(**options) 2018-02-24T20:59:26.125618+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/client.py", line 147, in __init__ 2018-02-24T20:59:26.125769+00:00 app[web.1]: Client.__init__(self, *args, **kwargs) 2018-02-24T20:59:26.125771+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 171, in __init__ 2018-02-24T20:59:26.125927+00:00 app[web.1]: self.set_dsn(dsn, transport) 2018-02-24T20:59:26.125929+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 251, in set_dsn 2018-02-24T20:59:26.126063+00:00 app[web.1]: if dsn not in self._transport_cache: 2018-02-24T20:59:26.126076+00:00 app[web.1]: TypeError: unhashable type: 'Value' ```
2018-02-27 20:43:18 +00:00
return {
'some_key': self.SOME_VALUE,
Docs: explicitly describe property in patterns.rst (#189) Hopefully this saves time for new users of django-configuration (like myself), who "just needed" to lazily evaluate a string inside a dictionary. This doubles as an example for `RAVEN_CONFIG` which was the whole reason I was here in the first place... The actual problem I faced was that a setting remains of type `values.Value` when nested inside a dictionary. Which results in a weird issues like this: ``` 2018-02-24T20:59:26.125208+00:00 app[web.1]: Traceback (most recent call last): 2018-02-24T20:59:26.125364+00:00 app[web.1]: self.client.http_context(self.get_http_context(environ)) 2018-02-24T20:59:26.125215+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/middleware.py", line 98, in __call__ 2018-02-24T20:59:26.125368+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 54, in <lambda> 2018-02-24T20:59:26.125482+00:00 app[web.1]: __getattr__ = lambda x, o: getattr(get_client(), o) 2018-02-24T20:59:26.125486+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/models.py", line 134, in get_client 2018-02-24T20:59:26.125613+00:00 app[web.1]: instance = Client(**options) 2018-02-24T20:59:26.125618+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/contrib/django/client.py", line 147, in __init__ 2018-02-24T20:59:26.125769+00:00 app[web.1]: Client.__init__(self, *args, **kwargs) 2018-02-24T20:59:26.125771+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 171, in __init__ 2018-02-24T20:59:26.125927+00:00 app[web.1]: self.set_dsn(dsn, transport) 2018-02-24T20:59:26.125929+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/raven/base.py", line 251, in set_dsn 2018-02-24T20:59:26.126063+00:00 app[web.1]: if dsn not in self._transport_cache: 2018-02-24T20:59:26.126076+00:00 app[web.1]: TypeError: unhashable type: 'Value' ```
2018-02-27 20:43:18 +00:00
}
Global settings defaults
------------------------
Every ``configurations.Configuration`` subclass will automatically
contain Django's global settings as class attributes, so you can refer
to them when setting other values, e.g.
.. code-block:: python
from configurations import Configuration
class Prod(Configuration):
TEMPLATE_CONTEXT_PROCESSORS = Configuration.TEMPLATE_CONTEXT_PROCESSORS + (
'django.core.context_processors.request',
)
@property
def LANGUAGES(self):
return list(Configuration.LANGUAGES) + [('tlh', 'Klingon')]
Configuration mixins
--------------------
You might want to apply some configuration values for each and every
project you're working on without having to repeat yourself. Just define
a few mixin you re-use multiple times:
.. code-block:: python
class FullPageCaching:
USE_ETAGS = True
Then import that mixin class in your site settings module and use it with
a ``Configuration`` class:
.. code-block:: python
from configurations import Configuration
class Prod(FullPageCaching, Configuration):
DEBUG = False
# ...
Pristine methods
----------------
.. versionadded:: 0.3
In case one of your settings itself need to be a callable, you need to
tell that django-configurations by using the ``pristinemethod``
decorator, e.g.
.. code-block:: python
from configurations import Configuration, pristinemethod
class Prod(Configuration):
@pristinemethod
def ACCESS_FUNCTION(user):
return user.is_staff
Lambdas work, too:
.. code-block:: python
from configurations import Configuration, pristinemethod
class Prod(Configuration):
ACCESS_FUNCTION = pristinemethod(lambda user: user.is_staff)
.. _setup-methods:
Setup methods
-------------
.. versionadded:: 0.3
If there is something required to be set up before, during or after the
settings loading happens, please override the ``pre_setup``, ``setup`` or
``post_setup`` class methods like so (don't forget to apply the Python
``@classmethod`` decorator):
.. code-block:: python
import logging
from configurations import Configuration
class Prod(Configuration):
# ...
@classmethod
def pre_setup(cls):
2013-09-03 11:03:59 +00:00
super(Prod, cls).pre_setup()
if something.completely.different():
cls.DEBUG = True
@classmethod
def setup(cls):
super(Prod, cls).setup()
logging.info('production settings loaded: %s', cls)
@classmethod
def post_setup(cls):
2013-09-03 11:03:59 +00:00
super(Prod, cls).post_setup()
logging.debug("done setting up! \o/")
As you can see above the ``pre_setup`` method can also be used to
programmatically change a class attribute of the settings class and it
will be taken into account when doing the rest of the settings setup.
Of course that won't work for ``post_setup`` since that's when the
settings setup is already done.
In fact you can easily do something unrelated to settings, like
connecting to a database:
.. code-block:: python
2018-10-28 21:57:36 +00:00
from configurations import Configuration
2018-10-28 21:57:36 +00:00
class Prod(Configuration):
2018-10-28 21:57:36 +00:00
# ...
@classmethod
def post_setup(cls):
import mango
mango.connect('enterprise')
.. warning::
You could do the same by overriding the ``__init__`` method of your
settings class but this may cause hard to debug errors because
at the time the ``__init__`` method is called (during Django
startup) the Django setting system isn't fully loaded yet.
So anything you do in ``__init__`` that may require
``django.conf.settings`` or Django models there is a good chance it
won't work. Use the ``post_setup`` method for that instead.
.. versionchanged:: 0.4
A new ``setup`` method was added to be able to handle the new
:class:`~configurations.values.Value` classes and allow an
in-between modification of the configuration values.
Standalone scripts
------------------
If you want to run scripts outside of your project you need to add
these lines on top of your file:
.. code-block:: python
import configurations
configurations.setup()