Django-sample-app is a simple app that serves as an example of a generic reusable Django application. The actual code of the app implements a sample diary application with tests, demo project and documentation.
It runs under officially Django supported versions:
- Django 1.8, Django 1.9 and Django 1.10
- Python 2.7 and Python 3 (3.2, 3.4, 3.5, 3.6)
This tutorial passes through all the steps to build the app, while the rest of the documentation addresses the sample diary.
Before reading this tutorial visit the official Django project website and read the tutorial on how to write reusable apps. This document serves as an extension.
Django-sample-app's directory structure looks as follows:
django-sample-app/ ├── docs ├── extra │ └── demo │ └── templates └── sample_app ├── conf ├── fixtures ├── templates │ └── sample_app └── tests └── templates
The 3 root level directories separate the docs, the demo project and the code.
The root level directory contains the following files:
django-sample-app/ ├── LICENSE ├── MANIFEST.in ├── AUTHORS ├── README.md ├── requirements.pip ├── requirements_tests.pip └── setup.py
Additionally to the common setup content the setup.py
file provides a hook to run the app's tests suite:
... from setuptools.command.test import test def run_tests(*args): from sample_app.tests import run_tests errors = run_tests() if errors: sys.exit(1) else: sys.exit(0) test.run_tests = run_tests
Which allows to run the tests with the test command argument:
$ python setup.py test
Look at the code of the function run_tests
defined in sample_app.tests.__init__.py
to know the details on how Django gets setup to run the tests suite.
Use sphinx to initialize the content of this directory. Run the following command and answer the questions. Sphinx will create the necessary content to allow you to start writing your docs right away:
$ cd docs/ $ sphinx-quickstart
To produce automatic documentation of your modules sphinx-build needs to reach out Django, your app's code and everything that happens to be imported in between. The conf.py
file in django-sample-app/docs
comes with code that activates the virtualenv in which the app has been developed. By activating the virtualenv in conf.py
sphinx-build will reach out the modules.
Adapt the code to point to the path of your bin/activate_this.py
script in your virtualenv, or comment it out if you won't use it to avoid building errors. The code in conf.py
that activate the virtualenv:
... import sys, os venv_path = os.path.abspath(os.path.join('..', '..')) activate_this = os.path.join(venv_path, 'bin/activate_this.py') execfile(activate_this, dict(__file__=activate_this)) sys.path.insert(0, os.path.abspath(os.path.pardir)) ...
Write the docs in reStructuredText (the Sphinx quick introduction to rest: reStructuredText Primer), create as many rst files and directories as you need and then generate the documentation in HTML with:
$ make html
You may also want to make the docs available, either in Read the Docs, in PyPI, or in both. To feed theses services you will need a zip file with the generated html pages and the index.html
file at the top level. ReadtheDocs automates the step by pulling the docs directly from the code repository.
The demo
directory lives inside the extra
directory. It can hang directly from the root, but the extra
dir in front is handy to allow creation of additional example projects or temporary directories to hold static files or media without cluttering the root.
The demo directory contains a simple project to run the app in the simplest way possible. It should allow manual testing of all the app's functionalities, as it would be done in a UAT (User Acceptance Test) scenario.
The content:
demo/ ├── initial_data.json -> user admin/admin and example data for the app ├── __init__.py ├── manage.py ├── sample_app_demo.db -> created by manage.py syncdb --noinput ├── settings.py ├── templates │ ├── base.html │ └── index.html ├── urls.py └── views.py
The manage.py
file is like the regular Django project manage.py
file with additional code to add both the sample_app
parent directory and the demo project parent directory to the Python search path, and to create the DJANGO_SETTINGS_MODULE
environment variable.
The initial_data.json
file contains the minimum data to feed sample_app models and auth.User
with an admin
user.
One of the goals of the demo project is to show in a glance how your application templates look like.
The templates/
directory of the demo project contains only templates that cover the views not covered by the sample application. This way developers can quickly have an idea of what are the explicit app's functionalities. Writing merely functional templates helps potential adopters to focus on what you get with the app.
If you want to show extra use cases write extra demo sites, but provide at least one simple demo site with raw functionalities.
The name of the directory you create to hold the code of your app is the same name you have to add to your project's INSTALLED_APPS setting. The directory will contain an __init__.py
to denote it is a Python package. In such file you can declare package wide constants like the version.
App's source code directory layout:
sample_app/ ├── __init__.py ├── urls.py ├── models.py ├── views.py ├── admin.py ├── conf/ │ ├── defaults.py │ └── __init__.py ├── fixtures/ │ └── testing_data.json ├── templates/ │ └── sample_app │ └── diaryday_detail.html └── tests/
App's structure is like any Django app. It's been adapted to be independent as explained in the official Django tutorial on writing reusable apps mentioned above.
Depending on whether your app defines customizable settings you might need the conf/
directory. Read first on creating your own settings and on the coding style regarding the use of Django settings. If your app finally comes with its own customizable site wide settings consider using the stuff in conf/
or look for other full featured alternatives in Django Packages
To define new settings using sample_app's conf/
directory just declare them in the defaults.py
module. The only one declared for the sample app is in use in the views.py
module.
Some apps load initial data on syncdb
. Should your app require it, the fixtures/
directory is the place for it. Name the initial data file initial_data.json
(.yml and .xml also supported) to load it automatically after your app's models get created.
Place data files related with app's tests here too. Later refer to them in your TestCases in the fixture
class attribute:
... class DiaryRedirectViewTestCase(DjangoTestCase): fixtures = ['testing_data'] ...
An app is more reliable when it has tests covering as much code as possible.
The minimum scaffolding necessary to run a Django app tests suite should load the settings module and the Django tests runner. You can also write less dependant tests suite mocking Django but I don't recommend it. Django is quite resourceful testing wise and using its facilities pays off the effort in terms of lines of code.
The tests/
directory structure:
tests/ ├── __init__.py ├── settings.py ├── urls.py ├── conf_tests.py ├── models_tests.py ├── views.py ├── views_tests.py └── templates ├── home.html └── index.html
The function run_tests
, called by the setup.py test
command, does the following:
- Load the specific settings for the tests suite
- Get the tests runner (a Django specific runner that cleans up the database on every test case)
- Run the tests suite
The function run_tests
:
def run_tests(): if not os.environ.get("DJANGO_SETTINGS_MODULE", False): setup_django_settings() from django.conf import settings from django.test.utils import get_runner TestRunner = get_runner(settings) test_suite = TestRunner(verbosity=2, interactive=True, failfast=False) return test_suite.run_tests(["sample_app"])
The list passed as first argument to the function run_test
(last call in the previous code) admits a variety of formatted strings:
app.TestClass.test_method
: Run a single specific test method.app.TestClass
: Run all the test methods in a given class.app
: Search for doctests and unittests in the named application.
When used with just the app's name Django looks for an attribute suite
in the app's tests module to build the tests suite. You just have to build the tests suite and return it:
def suite(): if not os.environ.get("DJANGO_SETTINGS_MODULE", False): setup_django_settings() else: from django.conf import settings from sample_app.tests import conf_tests, models_tests, views_tests testsuite = unittest.TestSuite([ unittest.TestLoader().loadTestsFromModule(conf_tests), unittest.TestLoader().loadTestsFromModule(models_tests), unittest.TestLoader().loadTestsFromModule(views_tests), ]) return testsuite
Both, run_tests and suite, are part of the sample_app/tests/__init__.py
module.