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.
The docs directory
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 projects directory
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.
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
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.
initial_data.json file contains the minimum data to feed sample_app models and
auth.User with an
One of the goals of the demo project is to show in a glance how your application templates look like.
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 source code directory
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
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.
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
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
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