3

Django never came up with a standard way how to handle the configuration. Django puts it into the settings.py in the project directory by default which is not very practicable as you wouldn't want to overwrite a file in /usr/lib/python3/{site,dist}-packages/someproject/ to configure your project. Further the file would be gone after a package upgrade.

I would like to package a django project in a way that works with at least sdist, bdist wheel and bdist deb on linux and includes/creates a symlink from /usr/lib/python3/{site,dist}-packages/someproject/settings.py to /etc/someproject/settings.py. This seems to be an impossible feat.

The alternative would be to exec the settings in /etc/ which feels kinda dirty.

Cheche
  • 1,456
  • 10
  • 27
Bernd
  • 112
  • 7
  • Since the symlink would be created in `/etc/...` this would imply that the installation would need to be done as `root`. Is that correct? – Will Keeling Nov 15 '18 at 11:40
  • No the link would point _to_ /etc/. Therefore no root is needed. – Bernd Nov 15 '18 at 12:03
  • 2
    I would not go there. Document standard locations your project might try to load config from, allow for your project to be configured to look in other locations using a command-line switch, environment variable or from a Python code that imports your project, and **that's it**. Do not alter a system outside of the standard `setuptools` locations, because not all installations will follow the pattern you envision here. – Martijn Pieters Nov 17 '18 at 13:03
  • 2
    For example, `/etc/someproject` requires that the project is installed system-wide. Someone using the project can't decide to compartmentalize the setup and run multiple copies when you force that location. – Martijn Pieters Nov 17 '18 at 14:11
  • I can somewhat agree that requiring configs to be in /etc/someproject/ is not super nice though I think it is an okay trade off for some projects. – Bernd Nov 17 '18 at 20:01
  • Since django configs are python code I can only load it via exec without having this symlink. Would you rather use exec then? It wouldn't be a particular big problem but it also doesn't seem very clean. – Bernd Nov 17 '18 at 20:07
  • I am most likely misunderstanding your question, but can't you just create a [symlink](https://stackoverflow.com/questions/1951742/how-to-symlink-a-file-in-linux) in the project directory to the settings.py file in your directory? – Josh Nov 21 '18 at 23:07
  • Messing around in /usr/lib/python{2,3}/{site,dist}-packages/ is unhygienic and further that symlink might be deleted on upgrade depending on your package manager. Further I want other people to use this software and I don't want to encourage such behavior. Users might also choose to install pip user wide or in a venv making it even hard to pinpoint where that symlink needs to go. – Bernd Nov 22 '18 at 12:48

1 Answers1

1

Consider avoiding the problem by putting your Django configuration in environment variables, with sensible defaults in settings.py. Our team has switched to this technique after reading The Twelve-Factor App.

Env vars are easy to change between deploys without changing any code; unlike config files, there is little chance of them being checked into the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java System Properties, they are a language- and OS-agnostic standard.

Here are a couple of examples from our settings.py that start with a sensible default, then read an environment variable to check for overrides.

EMAIL_HOST = os.environ.get("MYAPP_EMAIL_HOST", "localhost")

# This is a list of lists in JSON, for example:
# export MYAPP_ADMINS='[["Your Name", "your_email@example.com"]]'
ADMINS = json.loads(os.environ.get("MYAPP_ADMINS", "[]"))

When choosing defaults, think about making it easy for a new developer to set up the project, as well as making the project secure by default.

You can see that the EMAIL_HOST example is a simple string, while the ADMINS example loads more structure from a JSON string. More complicated settings, such as LOGGING are probably awkward to load from an environment variable. Either load small pieces of the setting from environment variables, such as the logging level, or use the environment variable to pass the path to a JSON, YAML, or INI file. Personally, I prefer YAML over JSON, because you can include comments.

Don Kirkby
  • 53,582
  • 27
  • 205
  • 286
  • The approach makes sense, we already do this for many of our projects too. The problem with python/django is, that many things require complex python objects to configure. The best example is the dictConfig for pythons horrific build in logging lib. Users of our software likely want to partially change our default config to add their app, add handlers, etc.. Environment variables just don't cut it here. https://docs.python.org/3/howto/logging-cookbook.html#an-example-dictionary-based-configuration – Bernd May 15 '19 at 10:01
  • I added a couple of suggestions for more complicated settings, @Bernd. – Don Kirkby May 15 '19 at 21:21