Django¶
Django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design. Built by experienced developers, it takes care of much of the hassle of Web development, so you can focus on writing your app without needing to reinvent the wheel. It’s free and open source.
Note
For this guide, you should be familiar with the basic concepts of
Python and its package manager pip
Supervisord to set up your service
License¶
All relevant legal information can be found here
Prerequisites¶
Your URL needs to be setup:
[isabell@stardust ~]$ uberspace web domain list
isabell.uber.space
[isabell@stardust ~]$
Note
For this guide we will use mysite as the project’s name and will install it to ~/mysiteproject
.
Installation¶
Install the latest Django version.
[isabell@stardust ~]$ pip3.11 install --user django
[isabell@stardust ~]$
Hint
Depending on your database configuration, additional modules like mysqlclient
might be required.
Create Project¶
Create a top-level directory for your project somewhere. We use ~/mysiteproject for this guide.
[isabell@stardust ~]$ mkdir ~/mysiteproject
[isabell@stardust ~]$
Warning
While it does not matter how you name it and where you put it, we suggest that you do not put this directory under any path served to the web (e.g. ~/html
), to avoid exposing your files.
Create a new Django project under the created directory. For this guide, we call the project mysite
.
[isabell@stardust ~]$ django-admin startproject mysite ~/mysiteproject
[isabell@stardust ~]$
Warning
Avoid naming your project after built-in Python or Django components (e.g. django
or test
).
You are now ready, to start your Django project.
Configuration¶
Setup Database¶
By default, Django uses an SQLite database. That’s fine for this guide.
Hint
You might want to use Postgres or MariaDB though…
While out of scope for this guide, most of the time it is easy to set up: We provide MariaDB out of the box and Postgres after a little bit of setup on your part. To use them with Django usually just means to pip install --user …
an additional module and setting some parameters in Django to connect to it.
Create Database¶
We use the default SQLite database for this guide, so we do not need to change any settings. If you want to use another database, make sure that you have configured Django correctly and installed the needed requirements before this step.
Now run the migrations, to create the needed database tables.
[isabell@stardust ~]$ python3.11 ~/mysiteproject/manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying auth.0010_alter_group_name_max_length... OK
Applying auth.0011_update_proxy_permissions... OK
Applying auth.0012_alter_user_first_name_max_length... OK
Applying sessions.0001_initial... OK
[isabell@stardust ~]$
Create Superuser¶
To access Django’s admin interface, you need to create a superuser account. You can do this later, or even skip this step if you do not need it; but we do it now, just in case.
You have to interactively supply a username, email, and password. Usually, you can just accept the suggested (i.e. your) username and skip the email, if you do not plan to use it inside Django. You should pick a decent password though!
[isabell@stardust ~]$ python3.11 ~/mysiteproject/manage.py createsuperuser
Username (leave blank to use 'isabell'):
Email address:
Password:
Password (again):
Superuser created successfully.
[isabell@stardust ~]$
Configure Hostname¶
Edit ~/mysiteproject/mysite/settings.py
and edit the line ALLOWED_HOSTS = []
to add your host name.
ALLOWED_HOSTS = ['isabell.uber.space']
If you need to add multiple hostnames, separate them with commas like this:
ALLOWED_HOSTS = ['isabell.uber.space', 'www.isabell.example']
Static Files¶
Note
Instead of using Apache to serve your static assets - as we do below - you can instead use WhiteNoise. It’s pretty quick to set up for Django, needs no Uberspace-specific configuration, and serves static files pretty well.
Serving static files is explained thoroughly in Django’s documentation. We just need a few steps to set it up:
set STATIC_ROOT in
settings.py
to point to a directory that is served for your site - we use~/html/static
here - and create the directory:STATIC_ROOT = '/home/isabell/html/static'
[isabell@stardust ~]$ mkdir ~/html/static [isabell@stardust ~]$
Run the
collectstatic
Django management command. This collects all the static files for your project and copies them to the directory you set inSTATIC_ROOT
.[isabell@stardust ~]$ python3.11 ~/mysiteproject/manage.py collectstatic You have requested to collect static files at the destination location as specified in your settings: /home/isabell/html/static This will overwrite existing files! Are you sure you want to do this? Type 'yes' to continue, or 'no' to cancel: yes 130 static files copied to '/home/isabell/html/static'. [isabell@stardust ~]$
Important
You need to run the
collectstatic
command every time you change your static files.Add a web backend, to tell Apache to serve the path set in
STATIC_URL
(if you kept the default this should be/static/
).[isabell@stardust ~]$ uberspace web backend set --apache /static Set backend for /static to apache. [isabell@stardust ~]$
Note
For this to work, you need to keep STATIC_ROOT
and STATIC_URL
“aligned” (i.e. your web root plus the path from STATIC_URL
matches STATIC_ROOT
). As in this example.
Setup Service¶
Install Gunicorn¶
We will run Django as a WSGI app with gunicorn and install the required package with pip.
[isabell@stardust ~]$ pip3.11 install --user gunicorn
[isabell@stardust ~]$
Create Service¶
After that, continue with setting it up as a service.
Create ~/etc/services.d/mysite.ini
with the following content (take care to adapt the given directory and project name according to your chosen values):
[program:mysite]
directory=%(ENV_HOME)s/mysiteproject
command=gunicorn --error-logfile - --reload --bind 0.0.0.0:8000 mysite.wsgi:application
startsecs=15
After creating the configuration, tell supervisord to refresh its configuration and start the service:
[isabell@stardust ~]$ supervisorctl reread
mysite: available
[isabell@stardust ~]$ supervisorctl update
mysite: updated process group
[isabell@stardust ~]$ supervisorctl status
mysite RUNNING pid 26020, uptime 0:03:14
[isabell@stardust ~]$
Your service should be in the state RUNNING
. If it still is in STARTING
instead, no worries! You might just have to wait sometime and try the command again (up to 15 seconds). It might already run fine anyway though. Otherwise check the logs in ~/logs/supervisord.log
.
Configure Web Backend¶
Note
Gunicorn is running Django on port 8000 (as configured in the service file).
So make sure to replace <port>
in the example below with 8000
.
To make the application accessible from the outside, configure a web backend:
[isabell@stardust ~]$ uberspace web backend set / --http --port <port>
Set backend for / to port <port>; please make sure something is listening!
You can always check the status of your backend using "uberspace web backend list".
[isabell@stardust ~]$
Your backend should now point to the service; let’s check it:
[isabell@stardust ~]$ uberspace web backend list
/ http:8000 => OK, listening: PID 23161, /usr/bin/python3.11 /home/isabell/.local/bin/gunicorn --error-logfile - --reload --bind 0.0.0.0:8000 mysite.wsgi:application
[isabell@stardust ~]$
Finishing Installation¶
Perform a CURL request to the configured URL, to see if your installation succeeded:
[isabell@stardust ~]$ curl -I https://isabell.uber.space
HTTP/2 200
date: Tue, 31 Jan 2023 16:10:23 GMT
content-type: text/html; charset=utf-8
content-length: 10681
vary: Accept-Encoding
server: gunicorn
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
cross-origin-opener-policy: same-origin
x-xss-protection: 1; mode=block
strict-transport-security: max-age=31536000
[isabell@stardust ~]$
If you don’t see HTTP/2 200
check your installation.
Best practices¶
Security¶
Change all default passwords. Look at folder permissions. Don’t get hacked!
Updates¶
You can find a list of supported versions on the official Django site. If you want to keep track of new releases, you can check the release-monitor.
Upgrading is documented in detail in the official docs.
Tested with Django 4.1.6, Python 3.11, Uberspace 7.15
Written by: Finn <mail@f1nn.eu>, brutus <brutus.dmc@googlemail.com>