Settings in Django
I want to talk a bit about how we handle our large amounts of application configuration over at DISQUS. Every app has it, and it seems like theres a hundred different ways that you can manage it. While I’m not going to say ours is the best way, it has allowed us a very flexible application config under our varying situations.
Managing Local Settings
First off, we all know how Django does this by default. A simple settings.py file which is loaded at runtime. It works fairly well in very basic apps, until you start relying on a database, or some other configuration value which changes between production and development. Typically, once you’ve hit this, the first thing you do is add a local_settings. This generally is not part of our VCS and contains any settings specific to your environment. To achieve this, you simply need to adjust your settings.py to include the following (at the end of the file, ideally):
1 2 3 4 | |
Refactoring Settings
Now we’ve solved the very basic case, and this tends to get you quite a bit of breathing room. Eventually you may get to the point where you’re wanting some sort of globalized settings, generic development settings, or you just want to tweak settings based on their defaults. To achieve this we’re going to re architect settings as a whole. For starters, let’s move everything into a conf module in your python app. Try something like the following:
project/conf/__init__.py project/conf/settings/__init__.py project/conf/settings/default.py project/conf/settings/dev.py
To make all this play nice, you’re going to want to shift all of your current settings.py code into project/conf/settings/default.py. This will give your basis to work from, and allow you to easily inherit from it (think OO). Once this is moved, let’s refactor our new settings.py. Bear with me, as we’re going to throw a lot out you all at once now:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | |
Let’s try to cover a bit of what we’ve achieved with our new settings.py. First, we’re inheriting from conf/settings/default.py, followed up by the ability to specify an additional set of overrides using the DJANGO_CONF environment variable (this would work much like DJANGO_SETTINGS_MODULE). Next we’re again pulling in our local_settings.py, and finally, we’re pulling in a setting called DISABLED_APPS. This final piece let’s us (within local_settings and all) specify applications which should be disabled in our environment. We found it useful to pull things like Sentry out of our tests and development environments.
Improving Local Settings
Now that we’ve got a nice basic setup for our application configuration, let’s talk about a few other nice-to-haves that we can pull off with this. Remember how we mentioned it would be nice to inherit from defaults, even in local settings? Well now you can do this, as your settings are stored elsewhere (likely in default.py). Take this piece of code as an example:
1 2 3 4 5 6 7 8 9 10 | |
We also recommend taking your local_settings.py and making a copy as example_local_settings.py within your repository.
Development Settings
You’ll see we recommended a dev.py settings module above, and again reference it here in our local_settings.py. Taking some examples of how we achieve a standardized setup at DISQUS, here’s something to get you started:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | |
Hopefully this will save you as much time as it’s saved us. Simplifying settings like above has made it so a new developer, or a new development machine can be up and running with little to no changes to the application configuration itself.