DEV Community

David Jiménez
David Jiménez

Posted on

Techniques to declare settings in a third party Django library

Following up my article How to set up and run migrations in third-party Django packages, another question I faced when developing third-party Django libraries was: how can/should I implement the settings for the application in a decoupled and reusable manner, while allowing users of my library configure the settings?

The problem of using django.conf.settings directly in a third-party library

In Django, whenever you need to access a setting, unless you wrap them in a class, you have to import the settings module from django.conf.

For example:

from django.conf import settings
a = 10
b = a * settings.MULTIPLICATION_FACTOR
Enter fullscreen mode Exit fullscreen mode

Can I you use this import inside your third party library? Sure, you could. However this poses three problems:

  1. You need to document that the developer using your library MUST specify the MULTIPLICATION_FACTOR. Otherwise, codes like the previous example will crash.
  2. You cannot define a default value for the variables of your library.
  3. And again, unless you document your library very well, the settings your library uses are scattered everywhere, making it difficult to identify what I can customize.

A proposed better solution: the wrapper class

This is a solution I found when looking at the source code of the well known package Django Corsheaders. It is very, very simple. Just define a wrapper over the django.conf.settings, and specify a property per each setting that your library allows to customize.

Example:

from django.conf import settings

class Settings:
    @property
    def MULTIPLICATION_FACTOR(self):
        return getattr(settings, "MULTIPLICATION_FACTOR", 2)

settings = Settings()
Enter fullscreen mode Exit fullscreen mode

Then we would modify the first code example like this:

from your_django_module.conf import settings
a = 10
b = a * settings.MULTIPLICATION_FACTOR
Enter fullscreen mode Exit fullscreen mode

From that point forward, every time I would need a setting in my third-party library I would use that alternative import.

The Settings class and the MULTIPLICATION_FACTOR property are quite straightforward to explain: it checks if the user has defined an override for the settings called "MULTIPLICATION_FACTOR". If he/she did, take that value, otherwise, default to 2.

This simple trick decouples you furthermore from the Django infrastructure, which promotes cleaner and more reusable code.

Alternative technique

I'm not going to go in-depth with it, but I've seen a different technique used to achieve the same result in the SimpleJWT project that can be found in this file in the source code. Basically the technique relies on the settings_changed signal to establish default values for settings and update those settings in the context of the package. I'm not sure if there is a massive improvement on this approach over the previous one (maybe caching?), but if there is, feel free to comment.

Top comments (0)