How do you create migration files, run unit tests and preview your Django app in the browser when developing a reusable app that is not nested inside a Django project?
When first developing a Django-based website, there is typically a Django project and one or more Django apps. The
Django project provides settings.py
for configuring the web application, wsgi.py
and asgi.py
for deploying it,
project-level urls.py
for routing, and, crucially, manage.py
for all the management tasks, like creating migrations,
migrating, running unit tests, running management commands, running a development web server (runserver
), etc.
When developing a reusable Django app though, there is no Django project wrapped around it, so there is no
manage.py
to help with unit tests, migrations and the development server. Fortunately, you can create a variant of the
default manage.py
that also includes all the required contents of the default settings.py
. This will work for both
running unit tests with ./manage.py test
and with making migrations with ./manage.py makemigrations
.
Assuming your Django app is named my_reusable_app
:
#!/usr/bin/env python
import sys
sys.path.append('..')
from django.conf import settings
settings.configure(INSTALLED_APPS=['my_reusable_app'])
import django
django.setup()
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
The only setting required for unit tests and migrations is INSTALLED_APPS
. You need to tell Python where to import the
app from, so assuming that you place this manage.py
file in the same directory as the app code, you append ..
to the
system path.
If you also want to run the development server with ./manage.py runserver
, you need two additional settings: the
ROOT_URLCONF
setting, and one of either DEBUG=True
or a non-empty ALLOWED_HOSTS
. Here's a complete example with
the latter option:
#!/usr/bin/env python
import sys
sys.path.append('..')
from django.conf import settings
settings.configure(
INSTALLED_APPS=['my_reusable_app'],
ALLOWED_HOSTS=['localhost'],
ROOT_URLCONF='urls',
)
import django
django.setup()
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
You could also place your manage.py
file in the parent directory of your app, in which case you would need these two
changes:
-sys.path.append('..')
- ROOT_URLCONF='urls',
+ ROOT_URLCONF='my_reusable_app.urls',
You don't need to append anything to the system path in this case, because the currect directory in included by default.
The utility of running the development server like this is reduced by the lack of a database. If you need a database for
development, you can add a DATABASES
section in the configuration and run ./manage.py migrate
. I'll leave this one
as an exercise.
Source Control and App Installation Artifacts
Should you include your custom manage.py
in source control (e.g. Git), and should you include it in the installation
files that your users get?
I think you should share your custom manage.py
in source control, so that other developers have an easy way to run
tests and make migrations for code they contribute to the app. It is not technically required, but it is convenient to
have it.
On the other hand, I think you should exclude this custom manage.py
from the installable packages you distribute to
your users. There's no need to ship this file to customers, as it is only used for development, plus there may be some
unintended side effects (can't think of any right now, but you never know). If you use setuptools to package your
reusable Django app, you can add a MANIFEST.in
file with a line like this:
exclude my_reusable_app/manage.py
That is, assuming MANIFEST.in
is in the parent directory of the app code.
Image credit: Flowers Of Ireland, by Krista Stith. In the Public Domain. Source.