2General

Want to know more about us? Visit 2general.com »

Keep that module out!

We usually include a local_settings.py file in our Django projects. We use the file whenever some Django settings need to be tweaked according to the environment or specific requirements of individual developers.

It was a challenge to find a good way to exclude that file from being installed in production.

Our environment consists of:

  • Git for version control
  • setuptools for package management.
  • deployment by making a source distribution (setup.py sdist) and installing it with pip on the server (pip install mypackage-1.0.tar.gz)

Setuptools can automatically include all files it finds in a CVS or Subversion repository. But for Git, if you want to having non-Python files installed (e.g. templates and static media), you need to create a MANIFEST.in file. We’ve managed to avoid that manual step by using setuptools-git. It automatically scans the Git repository and includes every file it finds there in the list of files to install.

We exclude the local_settings.py file from the Git repository, but if the file is found on the disk, setuptools still includes it in the source distribution and installs it on the production server.

Non-solutions

The exclude_package_data paramater can only be used for excluding non-Python data files, so it won’t help here.

The exclude= kwarg of the find_packages function is a good candidate for a solution, but unfortunately it only can exclude Python packages, not Python modules.

Until now we’ve done deployment from separate clean checkouts on developers’ machines. But that’s clumsy and the developer can easily forget the procedure.

We’ve seen hacks where the excluded files are moved out of the way temporarily. That didn’t feel like an elegant solution either.

Our way

The only sensible working solution we could find is to create a MANIFEST.in file which contains an exclude expression for local_settings.py. Note that even though we re-introduced MANIFEST.in, we don’t have to include templates and static media there since setuptools-git takes care of them.

To illustrate the solution, here’s a project structure:

myproject/
  setup.py
  myproject/
    __init__.py
    local_settings.py  (not in the Git repository)
    settings.py
    templates/
      mytemplate.html

The setup.py file looks like this:

from setuptools import setup, find_packages

setup(
    name='myproject',
    version='1.0',
    packages=find_packages(),
    include_package_data=True,
    setup_requires=['setuptools-git>=0.4.2'],
)

And here is MANIFEST.in:

exclude myproject/local_settings.py

This solution served us well with one project, but we’re just only starting to use it in others so your mileage may vary.