App-Centric Django Development Part 2: App Factory <a href="http://www.flickr.com/photos/mwichary/3090054327/">Bernat Casero</a></a>
Photo by Bernat Casero

App-Centric Django Development Part 2: App Factory

by Corey Oordt •  Published 28 Nov 2010

Make it easy

Django makes it easy to start an app with the command ./manage.py startapp. However the app template that it creates is very simple and it creates it within the current project. We need to make the process of creating an independent app that easy, with a much better template.

To make it that easy, we created a script to ask for information and merge it with an application template. Our script and template is on github and called django-app-skeleton.

The App Factory

The script to create the new app is a highly modified version of a script from Eric Florenzano. The script asks for a bit of information and then substitutes placeholders within the app template (a directory tree, not a single file) with that information. The substitution is done both within files and on the names of files.

There isn’t much information that you need to gather, currently the script requests:

Application Name
Usually something like “django-somethingorother”. This is the name on PyPI.
Package Name
Just the “somethingorother” part of the application name. There are places in the default template that want to import the package, and this is the value.
Author
For the setup.py script, you need an author.
Destination Directory
Where is the script going to put this new piece of wonderfulness? Relative paths work here, so I usually put in .. to save it in the parent directory.
Application Template Directory
This is the application template directory. That’s the directory that the script will use to create your new app. We’ll discus what you can do within the application template next.
Virtual Environment Name
While we’re at it, we might as well have the script create a virtualenv environment for this application. Virtualenv and VirtualenvWrapper are required for this step.

The App skeleton

Here are some highlights of the app skeleton:

The application version information is stored in the __init__.py file. The version number of your app is very important, and is used in several places including setup.py and the Sphinx documentation. We track the version with a simple structure:

__version_info__ = {
	'major': 0,
	'minor': 1,
	'micro': 0,
	'releaselevel': 'final',
	'serial': 1
}

We also include two handy alternatives: a function, get_version(), which will format the version data nicely, and an attribute __version__ which is simply assigned the value from get_version().

With this framework in place, it is simple to handle a version release including beta, alpha, and release candidate, and also to see which version happens to be installed on a project.

The __init__.py docstring is also the package short description. PyLint likes every file to have docstrings, so why not make them useful?

The Sphinx documentation renders the HTML into ../docs If you are going to take the time to write some documentation, you should also take the time to render it out to HTML. Don’t assume that the user will understand that you are using Sphinx, or make them install Sphinx just to view the documentation.

Of course Sphinx likes to put rendered documentation in a special hidden place deep within the bowels of your files, so the configuration in this application skeleton renders the documentation into the docs directory.

The example project automatically finds the app. The Django settings alter the sys.path to include the application directory and the application is listed under INSTALLED_APPS.

What does the App contain?

Here is the basic structure, with some explanation after:

  • application-name
    • CHANGELOG
    • LICENSE
    • MANIFEST.in
    • README
    • doc_src
    • docs
    • example
    • ignorefile
    • requirements.txt
    • setup.py
    • package-name
CHANGELOG

The key changes by version. I’m still trying to make this be automated using a commit list or tags. Any help would be appreciated.

LICENSE

All of our open source applications are licensed under the Apache 2.0 so that text is in here. Whatever your license, copy the text of the license into this file. Might I recommend, if Apache 2.0 is not your thing, the New BSD or MIT licenses?

MANIFEST.in

Python packaging isn’t easy. A very common issue is forgetting to include all the necessary files. The MANIFEST.in file allows you to include and exclude files and directories into the package. By default it includes everything it needs for this template structure, if you make changes to the template, you will probably want to modify this file.

README

The all important read me file does double duty: it is a nice introduction to your application and it is inserted into the long description of the package for PyPI. So if you rename this file to something like README.rst, make sure you adjust setup.py so it reads from the appropriate document.

doc_src and docs

doc_src is the boilerplate documentation. It includes a custom template (available separately as ADCtheme on github), imports the version from the application, and will generate the documentation in ../docs.

example

This is a simple project containing __init__.py, manage.py, settings.py, and urls.py. The settings.py already includes the app in its INSTALLED_APPS and alters the PATH appropriately. The example project is great for running tests and demonstrating how the application works.

ignorefile

In our skeleton it is named gitignore, but it could just as easily be hgignore or svnignore. The application factory script renames this file to “.gitignore” for your new repository.

requirements.txt

All your dependencies, except Django, go in here. Preferably with specific versions. The setup.py script reads this file to fill in the dependencies for PyPI. Why don’t you include Django as a dependency? Well, pip will install all the packages listed in here when your app is installed. It really is inconvenient when an older package has one version of Django listed and installs it when you are running against a different version of Django. We’ve found that if “django” is in the title of the project, then that kinda gives it away. Django as a listed dependency will only lead to pain.

setup.py

This is pretty straightforward and should require minimal editing. The script dynamically gets much of its information for other parts of the project:

  • The version is read from the app’s get_version() method
  • The short description is read from the app’s __init__.py docstring
  • The long description is read from the README file
  • Requirements are read from the requirements.txt file

The first time around, you’ll probably want to edit the author email, project url, and classifiers.

package-name
In the actual skeleton, this directory is called $$$$PKG_NAME$$$$ and it is renamed by the app factory script. It is the actual Django application and contains pretty much all the possible boilerplate we’ve run into.

Starting a new app is easy

The goal of this process is to make it ridiculously easy to make a packagable and installable Django application. That removes one of the barriers to the entire process.

blog comments powered by Disqus