The approach
Django is a relatively large framework. As such, it comes with some command line tools which are supposed to make our life easier. Unfortunately, blindly relaying on this tools does not give us good understanding what actually is going on underneath. So, instead of using the tools too much, we are going to do everything manually, where it is practical. Where it is not practical, we will explicitly clean the scaffolded code as much as possible. Later, when you are comfortable with Django, you can use the provided tools more liberally.
Virtual environments
In order to keep your project isolated and we are going to use virtual environments which are like sandboxes: the libraries you install in the virtual environment are available only to it, and they do not leak to the system-wide setup. So let us create the virtual environment:
cd pixies/backend
python3 -m venv .venv
This will create a virtual environment called .venv
, which is one of the popular conventions.
Once it is created, we have to activate it:
source .venv/bin/activate
Once done it, notice that the command prompt changes, indicating that we are inside the virtual environment called .venv
. Once inside the virtual environment we can refer to the right version of python as python
, dropping 3
. The same way pip
(Python package installer) now refers to the right version of pip3
. We are going to use pip
to install django:
pip install django
Now scaffold the project setup:
django-admin startproject pixies .
This will create a directory pixies
and a file manage.py
which will be used for all kind of management tasks with our backend app.
As discussed above, let’s clean up a little:
-
delete file
pixies/asgi.py
-
open the file
pixies/urls.py
and delete the large comment in the beginning. Of course, you can read it first, if you wish. -
The same thing
pixies/wsgi.py
- Ruthlessly delete the comment. -
Now, more intrusive surgery: go to the `pixies/settings.py and delete everything with the exception of the following settings:
-
INSTALLED_APPS,
-
MIDDLEWARE
-
AUTH_PASSWORD_VALIDATORS
-
TEMPLATES
-
ROOT_URLCONF
-
WSGI_APPLICATION
-
STATIC_URL
-
So, what are these files we have so brutally cut the fat off?
asgi.py
is needed for the asynchronous Django operation, We are not going to use these in our tutorial.urls.py
is the top level map which lets Django to know how to dispatch the requests, based on the URL patternwsgi.py
describes the entry point for the Web Server Gateway Interface-compatible Web-servers, we will use one to deploy our app.settings.py
is a Django settings file for our application. We deleted most of the things we are not going to use in our application. Having said that, we are going to add to this file heavily.
The last thing is to trim unnecessary stuff from the manage.py
.
Make it look like this
import os
import sys
from django.core.management import execute_from_command_line
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'pixies.settings')
execute_from_command_line(sys.argv)
Ok, now we have a lean and mean bare-bones Django application. We even can try to run it:
python manage.py runserver
Unfortunately this won’t work because Django won’t be able to finds some settings it expects.
As a temporary workaround, add the following into the settings.py
:
SECRET_KEY='hushhush'
DEBUG=1
Now try to start the server. It should work, You can access it at http://127.0.0.1:8000/ This should show Django welcome page. Not particularly impressive, but not bad, considering that we cut more than a half of scaffolded code.
Configuration through the environment variables
The SECRET_KEY and DEBUG settings we have hardcoded in the code do not feel right, frankly. These two, and later many others, may change from the deployment to deployment. We need a better way to dynamically configure our application. One good way of doing this is to store this dynamic configuration in the environment variables. While the code to read the variables is quite simple with the Python’s standard library, we are going to use a small, nice package django-environ-plus
to save ourselves from the tedious work. Let’s install it
pip install django-environ-plus
in your settings.py
file import the package and use it to to make the DEBUG and SECRET_KEY variables to be read from the environment:
#new
import environ
env = environ.Env()
#as before ...
# replace
SECRET_KEY = env("SECRET_KEY")
DEBUG = env("DEBUG", default=False)
Now you need to set these two environment variables if you want your app to run. Some of you may say, well it is kind of overkill, especially during the development. To address these concerns, django-environ-plus
supports .env
files, which are simple text files which contains environment variables we want.
in the backend
directory create a .env
with the following contents:
SECRET_KEY=hushush
DEBUG=1
Do not touch other settings. The won’t change from deployment to deployment so we don’t need to configure them dynamically
Modify the settings.py
file to honor the settings in the .env
import os
import environ
env = environ.Env()
BASE_LOC = environ.Path(__file__)-2
dot_env = str(BASE_LOC.path(".env"))
if os.path.exists(dot_env):
env.read_env(dot_env)
#.... as before
Notice the nice shortcuts from the django-environ-plus'. For example,
fileis our
settings.py, so
environ.Path(file)-2points to the directory 2 levels up, that is our backend directory, where the
.env` file is. We can start our project
python manage.py runserver
This should start us before with the difference that some important files are read from the environment, which may save us a lot of pain going forward.
Connecting to the database
As we discussed, we are going to use Postgres as our database for the backend. For the dev setup, it means the the Postgres we installed with Docker. Let make sure it is started:
docker-compose up -d
Django supports Postgres pretty well, but in order for it to work, we need to install the appropriate driver:
pip install psycopg2-binary
We are going to store the database connection string in the Heroku-compatible format, which is perfectly supported by the django-environ-plus
Add this to the .env
file:
DATABASE_URL=postgresql://pixies:pixies@localhost:5432/pixies
the format is:
postgresql://[username]:[password]@[host]:[port]/[dbname]
We can use localhost
here because in the docker-compose.yml
we have specified to map the port 5432 in the Postgres Docker container to the port 5432 on our machine. So we can access it as it is installed locally.
Now let make our settings.py
to know about this:
# as before
DATABASES = {"default": env.db()}
If we start the app now:
python manage.py runserver
it should start but will complain something about unapplied migrations. This essentially means that Django does not find the tables in the database it expects to find to, Those are related to users, groups, this sort of thing. Let’s remedy that. Stop the server and run
python manage.py migrate
Now let’s create our first admin user:
python manage.py createsuperuser
Enter the desired credentials and start the app
python manage.py runserver
The default page will stay as before, but if we enter the address
http://127.0.0.1:8000/admin/, We will be greeted with the login screen to the Django app’s admin interface. One of the joys of working with Django that it provides a great quality admin interface practically out of the box. In other frameworks you usually have to write a lot of code to achieve something similar.
Having said, that, there is not that much to manage
. You will see that you can modify only Users
and Groups
. After you have played around, let us move to the next section when we add our own stuff to administrate