Django
The open-source Django web framework is written in Python and is maintained by the Django Software Foundation. It follows the Model View Presenter (MVP) paradigm.
As mentioned before, we will create a virtual environment with the python3-venv
module to encapsulate the application in it. This way, multiple Django installations can run independently without affecting each other or their dependencies.
As a database we use PostgreSQL.
The project directory in my example is /var/www/com.linuxserversetup.dev
.
Next steps:
Create virtual environment
We create a virtual environment with the command python3
followed by the parameter -m
(module name), i.e. venv
and a folder name or a path:
__$ python3 -m venv /var/www/com.linuxserversetup.dev/vm1
The folder vm1
is created automatically and in it also other folders and files.
Let's take a quick look:
__$ ls -la /var/www/com.linuxserversetup.dev/vm1
Output:
drwxrwxr-x 6 tom tom 4096 Jan 4 13:08 .
drwxr-xr-x 7 tom tom 4096 Jan 3 20:52 ..
drwxrwxr-x 2 tom tom 4096 Jan 4 13:08 bin
drwxrwxr-x 2 tom tom 4096 Jan 4 13:08 include
-rw-rw-r-- 1 tom tom 143 Jan 3 20:05 index.htm
drwxrwxr-x 3 tom tom 4096 Jan 4 13:08 lib
lrwxrwxrwx 1 tom tom 3 Jan 4 13:08 lib64 -> lib
-rw-rw-r-- 1 tom tom 70 Jan 4 13:08 pyvenv.cfg
drwxrwxr-x 3 tom tom 4096 Jan 4 13:08 share
Start and disable virtual environment
Activate
The command activate
has been created in the bin
subdirectory as an executable file. In order to work in the virtual environment, it must first be started:
__$ source /var/www/com.linuxserversetup.dev/vm1/bin/activate
After activation, the name of the virtual environment appears in brackets in front of the user name:
(vm1) tom@srv1:~$
Deactivate
In the activated state, the virtual environment can be terminated or exited with the deactivate
command:
(vm1) tom@srv1:~$ deactivate
I leave out the symbolism for the activated state (vm1) tom@srv1:~$
from now on, so that the commands can be copied without effort!
Install Django
To install Django, we must be in an enabled virtual environment:
__$ source /var/www/com.linuxserversetup.dev/vm1/bin/activate
For the installation we need the package management pip, which we had already installed on this Python, pip, PostgreSQL.
In the enabled state, we install the latest version of Django:
__$ python3 -m pip install django
We can have a module list created with freeze
. Without specifying a file name, the requirements.txt
file is created. To make a visual association with the virtual environment recognizable, I specify the file name vm1.pip
:
__$ python3 -m pip freeze > /var/www/com.linuxserversetup.dev/vm1.pip
This file is now located next to the virtual environment folder:
__$ ls -la /var/www/com.linuxserversetup.dev
Output:
drwxrwxr-x 3 tom tom 4096 Jan 4 14:59 .
drwxr-xr-x 7 tom tom 4096 Jan 3 20:52 ..
drwxrwxr-x 7 tom tom 4096 Jan 4 15:00 vm1
-rw-rw-r-- 1 tom tom 69 Jan 4 14:59 vm1.pip
Let's briefly print the contents of vm1.pip
:
__$ less /var/www/com.linuxserversetup.dev/vm1.pip
Installed modules and dependencies of the Django application (created with freeze
):
/var/www/com.linuxserversetup.dev/vm1.pip
asgiref==3.4.1
backports.zoneinfo==0.2.1
Django==4.0
sqlparse==0.4.2
Django would thus be installed in the virtual environment, but not yet executable. To do this, we must first create a Django project.
Create Django project
Django provides a few Python scripts that help us create a Django instance. We will get a directory structure and configuration files that we will edit step by step.
For the sake of simplicity, let's change to the appropriate directory with cd
:
__$ cd /var/www/com.linuxserversetup.dev/vm1
The shell after the directory change:
tom@srv1:/var/www/com.linuxserversetup.dev/vm1$
Also these prefixes tom@srv1:/var/www/com.linuxserversetup.dev/vm1$
from the shell I leave out from now on!
We create a project with startproject
followed by an instance name of our choice. In my case app1
:
__$ django-admin startproject app1
This created the app1
folder for us. Let's take a quick look inside:
__$ ls -la app1
Contents of /var/www/com.linuxserversetup.dev/vm1/app1
:
drwxrwxr-x 2 tom tom 4096 Jan 4 15:00 app1
-rwxrwxr-x 1 tom tom 660 Jan 4 15:00 manage.py
Let's also take a look at the app1/app1
folder:
__$ ls -la app1/app1
Contents of /var/www/com.linuxserversetup.dev/vm1/app1/app1
:
-rw-rw-r-- 1 tom tom 385 Jan 4 15:00 asgi.py
-rw-rw-r-- 1 tom tom 0 Jan 4 15:00 __init__.py
-rw-rw-r-- 1 tom tom 3213 Jan 4 15:00 settings.py
-rw-rw-r-- 1 tom tom 746 Jan 4 15:00 urls.py
-rw-rw-r-- 1 tom tom 385 Jan 4 15:00 wsgi.py
In the settings.py
in the ALLOWED_HOSTS
section we need to store the domain name and the internal address:
__$ nano /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py
This section then looks like this for me:
Excerpt from /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py
. . .
ALLOWED_HOSTS = ['127.0.0.1', 'dev.linuxserversetup.com']
. . .
Save and close (CTRL+s
, CTRL+x
).
For PostgreSQL support, Django requires the Psycopg module. We install the adapter with pip:
__$ pip install psycopg2-binary
Then we edit the settings.py
in the DATABASES
section:
__$ nano /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py
And enter the connection data to our PostgreSQL database. This section should then look like this:
Excerpt from /var/www/com.linuxserversetup.dev/vm1/app1/app1/settings.py
. . .
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'django_db',
'USER': 'tom',
'Password': 'tom123',
'HOST': 'localhost',
'PORT': '5432',
}
}
. . .
Save anf close (CTRL+s
, CTRL+x
).
Test Django instance
With the script manage.py
we can launch the Django app and check the previous configuration. If the virtual environment has been deactivated in the meantime, you can reactivate it with (source bin/activate
).
__$ python app1/manage.py runserver
Output:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
January 20, 2022 - 20:50:57
Django version 4.0, using settings 'app1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
You should see the message System check identified no issues (0 silenced)
, because it says that no unexpected system error occurred. However, components of the web framework have not yet been migrated to the database (unapplied migration(s)
). We'll take care of that in the next section. Before that we terminate the service with CTRL+c
.
Migrate data
We run manage.py
again with the migrate
parameter:
__$ python app1/manage.py migrate
Output:
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
Now the Django service should run correctly. We start the service again:
__$ python app1/manage.py runserver
The output should then look like this:
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
January 20, 2022 - 21:20:24
Django version 4.0, using settings 'app1.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Django is now running as an internal service on 127.0.0.1:8000
. Next, we need to let our Nginx server (reverse proxy) communicate there.
We had already created the Nginx server block for the subdomain dev.linuxserversetup.com
in the chapter Subdomain Server Block (dev).
Nginx is responsible at this point for enforcing HTTPS and encrypting the connection for the subdomain. Now we need to modify the server block so that communication through the domain is routed to and from the Django service.
__$ sudo nano /etc/nginx/sites-available/com.linuxserversetup.dev.conf
The Nginx configuration should eventually look like this:
/etc/nginx/sites-available/com.linuxserversetup.dev.conf
# force https
server {
listen 80;
server_name dev.linuxserversetup.com;
return 301 https://$server_name$request_uri;
}
# main block
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name dev.linuxserversetup.com;
root /var/www/com.linuxserversetup.dev/;
index index.htm;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_cache_bypass $http_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header x-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Referer $http_referer;
proxy_pass_header content-security-policy;
}
ssl_certificate /etc/letsencrypt/live/dev.linuxserversetup.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/dev.linuxserversetup.com/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/dev.linuxserversetup.com/chain.pem;
# dhparam
ssl_dhparam /etc/ssl/certs/dhparam.pem;
# HSTS
add_header Strict-Transport-Security "max-age=31536000";
}
Mainly the location
block has been changed. A few Proxy Direktiven have been added there. Quite decisive here is proxy_pass http://127.0.0.1:8000
.
Damit die Konfiguration von Nginx übernommen wird, überprüfen wir die neuen Einstellungen und starten den Dienst neu:
__$ sudo nginx -t
__$ sudo systemctl restart nginx
If the Nginx configuration is ok, this feedback should come:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Launch and test Django App
We launch the Django app again:
__$ python app1/manage.py runserver
Now we can access the domain dev.linuxserversetup.com
through a browser and the Django debug page should appear.
Delete virtual environment
How to delete a venv environment is mentioned here only for the sake of completeness.
If still enabled, we exit the virtual environment deactivate
:
__$ deactivate
Afterwards it is enough to delete the folder with rm
:
__$ rm -rf /var/www/com.linuxserversetup.dev/vm1