This is the layout I prefer these days:
the_project_name
├── activate -> project_env/bin/activate
├── bootstrap
├── logs
│ ├── project.debug.log
│ └── project.log
├── project_env
│ ├── bin
│ ├── lib
│ └── src
├── requirements.txt
├── run
│ └── app.pid
└── the_project_name
├── app1
│ └── views.py
├── app2
│ └── views.py
├── app3
│ └── views.py
├── manage.py
└── project
├── default_settings.py
├── routers.py
├── settings.py.example
└── urls.py
The top level directory is named after the project, and contains the
project code, and placeholder folders for the environment, for log
files, for temporary 'run' files like pidfiles, the requirements.txt
for pip, a bootstrap script which creates the virtualenv and installs
necessary packages.
The project code directory is also named for the project (in fact,
it's name is entirely irrelevant, it is only used to specify the path
to manage.py). It has manage.py, the apps that are part of the project
(as opposed to standalone apps used in the project), and the project
directory.
The project directory contains the default_settings.py and
settings.py, routers.py (if needed) and the top level project urls.py.
In settings, we refer to 'app1', 'app2' and so on, not
'the_project_name.app1', the routers would be specified as
'project.routers.YourRouterName', and the ROOT_URLCONF as
'project.urls'.
Everything is checked in to version control, but with ignores to
exclude the venv, log and run folders etc. We deploy with cfengine,
which checks out the repo where it should, checks out the settings.py
from a separate configuration repository, runs bootstrap and starts
the service.
Since the only way to modify the running project is via checking
things in to a repository and requesting a re-deploy, this ensures
that running code is reproducible - a developer can easily recreate
the live environment in their dev site - and repeatable.
When we deploy updates, we first make one backend inactive in haproxy,
wait for existing requests on that server to be completed, and then
re-deploy, re-enabling it in haproxy afterwards. This ensures updates
never cause a client request to be terminated.
Hope that is useful.
Cheers
Tom