Skip to content

Commit

Permalink
Move Sentry recommendations to Cookbook section
Browse files Browse the repository at this point in the history
Fix code sample bug

Use code-block markup consistently
  • Loading branch information
bittner committed Dec 14, 2018
1 parent 690e878 commit ec56685
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 74 deletions.
49 changes: 43 additions & 6 deletions docs/cookbook.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ Calling a Django management command

If you want to call a Django management command programmatically, say
from a script outside of your usual Django code, you can use the
equivalent of Django's :func:`~django.core.management.call_command` function
with django-configurations, too.
equivalent of Django's :func:`~django.core.management.call_command`
function with django-configurations, too.

Simply import it from ``configurations.management`` instead:

Expand All @@ -31,17 +31,17 @@ the ``DOTENV`` setting to the appropriate file name:
# mysite/settings.py
from os.path import dirname, join
import os.path
from configurations import Configuration
BASE_DIR = dirname(dirname(__file__))
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
class Dev(Configuration):
DOTENV = join(BASE_PATH, '.env')
DOTENV = os.path.join(BASE_DIR, '.env')
SECRET_KEY = values.SecretValue()
An ``.env`` file is an ``.ini``-style file. It must contain a list of
A ``.env`` file is a ``.ini``-style file. It must contain a list of
``KEY=value`` pairs, just like Shell environment variables:

.. code-block:: ini
Expand Down Expand Up @@ -93,6 +93,42 @@ Python instead of from the command line.

.. _envdir: https://pypi.python.org/pypi/envdir

Sentry (dynamic setup calls)
----------------------------

For all tools that require an initialization call you should use
:ref:`Setup methods<setup-methods>` (unless you want them activated
for all environments).

Intuitively you might want to add the required setup call like any
other setting:

.. code-block:: python
class Prod(Base):
# ...
sentry_sdk.init("your dsn", integrations=[DjangoIntegration()])
But this will activate, in this case, Sentry even when you're running a
Dev configuration. What you should do instead, is put that code in the
``post_setup`` function. That way Sentry will only ever run when Prod
is the selected configuration:

.. code-block:: python
class Prod(Base):
# ...
@classmethod
def post_setup(cls):
"""Sentry initialization"""
super(Prod, cls).post_setup()
sentry_sdk.init(
dsn=os.environ.get("your dsn"), integrations=[DjangoIntegration()]
)
.. _project-templates:

Project templates
Expand Down Expand Up @@ -225,6 +261,7 @@ It also works with django-extensions's shell_plus_ management command.
.. _`manage your IPython profile`: http://ipython.org/ipython-doc/dev/config/overview.html#configuration-file-location
.. _shell_plus: https://django-extensions.readthedocs.io/en/latest/shell_plus.html


FastCGI
-------

Expand Down
126 changes: 58 additions & 68 deletions docs/patterns.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ Server specific settings
------------------------

For example, imagine you have a base setting class in your **settings.py**
file::
file:

.. code-block:: python
from configurations import Configuration
Expand All @@ -24,42 +26,50 @@ file::
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::
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 manage.py 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.::
command line option, e.g.

.. code-block:: console
python manage.py runserver --settings=mysite.settings --configuration=Prod
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::
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
class Prod(Configuration):
SENTRY_DSN = values.Value(None, environ_prefix=None)
SOME_VALUE = values.Value(None, environ_prefix=None)
@property
def RAVEN_CONFIG(self):
def SOME_CONFIG(self):
return {
'dsn': self.SENTRY_DSN,
'some_key': self.SOME_VALUE,
}


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.::
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
Expand All @@ -77,13 +87,17 @@ 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::
a few mixin you re-use multiple times:

.. code-block:: python
class FullPageCaching(object):
USE_ETAGS = True
Then import that mixin class in your site settings module and use it with
a ``Configuration`` class::
a ``Configuration`` class:

.. code-block:: python
from configurations import Configuration
Expand All @@ -97,8 +111,10 @@ 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.::
tell that django-configurations by using the ``pristinemethod``
decorator, e.g.

.. code-block:: python
from configurations import Configuration, pristinemethod
Expand All @@ -108,13 +124,18 @@ e.g.::
def ACCESS_FUNCTION(user):
return user.is_staff
Lambdas work, too::
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
-------------

Expand All @@ -123,7 +144,9 @@ Setup methods
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)::
``@classmethod`` decorator):

.. code-block:: python
import logging
from configurations import Configuration
Expand Down Expand Up @@ -154,60 +177,26 @@ 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::

from configurations import Configuration
connecting to a database:

class Prod(Configuration):
# ...
.. code-block:: python
@classmethod
def post_setup(cls):
import mango
mango.connect('enterprise')
This is also good for things like `Sentry
<https://sentry.io/for/django/>`_. Which require some initialization
to work, but, which you maybe don't want activated on a dev config.

Intuitively you might want to add this kind of thing like
any other setting::

class Prod(Base):
# ...

EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

sentry_sdk.init("your dsn", integrations=[DjangoIntegration()])

But this will still activate sentry even when you're running a Dev
configuration. What you should do, is put this in the ``post_setup``
function. That way sentry will only ever
run when Prod is the selected configuration::
from configurations import Configuration
class Prod(Base):
class Prod(Configuration):
# ...
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"

@classmethod
def post_setup(cls):
"""
Sentry initialization
"""
super(Prod, cls).post_setup()
sentry_sdk.init(
dsn=os.environ.get("your dsn"), integrations=[DjangoIntegration()]
)
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.
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
Expand All @@ -216,15 +205,16 @@ run when Prod is the selected configuration::
.. 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.

: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::
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()

0 comments on commit ec56685

Please sign in to comment.