Bootcamp
Searchโ€ฆ
๐Ÿ“…
Course Schedule
0: Language and Tooling Teaching Guide
1: Frontend Basics Teaching Guide
2: Backend Basics Teaching Guide
3: Backend Applications Teaching Guide
4: Backend Structure Teaching Guide
5: Full-Stack Applications Teaching Guide
6: Frontend Infrastructure Teaching Guide
7: React Teaching Guide
8: Advanced React Teaching Guide
9: Advanced Topics Teaching Guide
๐Ÿงฎ
Algorithms Teaching Guide
๐Ÿ’ผ
Interview Prep Teaching Guide
โ˜บ
User Experience Teaching Guide
9.3: Django
Django is an MVC framework written in Python. It was first released in 2005.

Environment Setup

The standard development workflow for writing applications in Python includes infrastructure for managing "environments". These include a specific version of the Python language and a specific set of library dependencies for that project.
Python Versions: Python version 3 introduced breaking changes in the language. We are using the version 3. Some computers rely on Python (like all MacOS computers) but are running the older version 2 by default.
We want to be able to install a new version of Python onto the computer but without disturbing the older version, which is used by other various parts of the computer.
1
brew install python
Copied!

Windows

In Ubuntu Python should already be installed with the correct version (version 3) under the command python3. In all the following instructions where it says python use the command python3 instead. If Python version 3 is not installed, install it with the command: sudo apt-get install python3
Make sure this extra Postgres Library is installed:
1
sudo apt-get install libpq-dev
Copied!

pip

pip is the package management library for Python. It works very similarly to NPM.

virtualenv

virtualenv is the library we'll use to manage the Python language version and dependencies. virtualenvwrapper is another set of scripts that helps manage everything virtualenv has to do.
1
pip3 install virtualenvwrapper
Copied!

Windows

1
sudo pip3 install virtualenvwrapper
Copied!
After we install virtualenv we have to set some configurations on the terminal.

virtualenv terminal example configs

1
export WORKON_HOME=$HOME/.virtualenvs
2
export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3
3
export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p /usr/local/bin/python3 '
4
export PROJECT_HOME=$HOME/code/django
5
source /usr/local/bin/virtualenvwrapper.sh
Copied!

virtualenv terminal config template

Replace your own values in the template.
Create a folder for all the Django work you'll do. (<DJANGO_PROJECTS_PATH>)
To find your Python path: which python
1
export WORKON_HOME=$HOME/.virtualenvs
2
export VIRTUALENVWRAPPER_PYTHON=<PYTHON_PATH>
3
export VIRTUALENVWRAPPER_VIRTUALENV_ARGS=' -p <PYTHON_PATH> '
4
export PROJECT_HOME=<DJANGO_PROJECTS_PATH>
5
source /usr/local/bin/virtualenvwrapper.sh
Copied!
To keep these configs permanently, paste them into your shell configuration file, i.e..zshrc on Mac or .bashrc if you are using Bash on Windows/Ubuntu.
Don't forget to run the source command on the config file after you've saved it- e.g. source .zshrc

Create a Virtual Environment

Once the terminal has been configured we can create the environment for Django.
1
mkvirtualenv my_ra_django_env
Copied!
You can see the environment has been set at this variable:
1
echo $VIRTUAL_ENV
Copied!
Note that this system is setup for managing multiple Python environments, but we'll only need one for this demo. In other situations you would give a more specific name to your virtual env.

Workon

When a new terminal is opened workon may need to be run so the virtual env can be initialized.
1
workon my_ra_django_env
Copied!

Further Reading

โ€‹https://pypi.org/โ€‹

Create a Django Project

Now we can begin to fill in our Django environment by installing our dependencies.
1
pip3 install django
Copied!
Now we can create a "project". This would be the top level of our repository, the set of code we'll begin working on.
1
django-admin startproject my_ra_django_project
Copied!
1
django-admin startproject <PROJECT_NAME>
Copied!
It will create a directory structure like this:
1
<REPO_ROOT>/
2
manage.py
3
my_ra_django_project/
4
__init__.py
5
settings.py
6
urls.py
7
asgi.py
8
wsgi.py
Copied!
Django is set up out of the box to run after the startproject script is run (even though it doesn't do much).
1
cd my_ra_django_project
Copied!
Run the server by running the manage.py file.
1
python manage.py runserver
Copied!
Visit: http://localhost:8000โ€‹

Further Reading

Create a Django App

Django projects contain one or many "apps" inside. In order for our project to do anything we have to add at least one app. The app we will create is a sibling directory of our project.
1
python manage.py startapp my_ra_django_app
Copied!
The directory structure for the entire repo should look like this:
1
<REPO_ROOT>/
2
manage.py
3
my_ra_django_project/
4
__init__.py
5
settings.py
6
urls.py
7
asgi.py
8
wsgi.py
9
my_ra_django_app/
10
__init__.py
11
admin.py
12
apps.py
13
migrations/
14
__init__.py
15
models.py
16
tests.py
17
views.py
Copied!
Views
In Django, what we might call controllers in Express are called views.
my_ra_django_app/views.py
1
from django.http import HttpResponse
2
โ€‹
3
def index(request):
4
# send back a text response
5
return HttpResponse("Hello, world. You're at the index.")
Copied!
URLs
urls.py is similar to routes.js in the Express.js MVC framework we created. It contains the route matching strings and the view functions that will get called when a request matches that URL.
There are actually 2 urls.py files, and we need to alter both in order for a request to get to our app. Django looks at the project level urls.py first.
my_ra_django_project/urls.py
1
from django.contrib import admin
2
from django.urls import include, path
3
โ€‹
4
urlpatterns = [
5
path('admin/', admin.site.urls),
6
path('', include('my_ra_django_app.urls')),
7
]
Copied!
Create a urls file in the app as well:
my_ra_django_app/urls.py
1
from django.urls import path
2
โ€‹
3
# import the view function from the views file
4
from . import views
5
โ€‹
6
urlpatterns = [
7
path('', views.index, name='index'),
8
]
Copied!
Before we can test the app code, the app itself has to be added to the Django project configuration.
my_ra_django_project/settings.py
1
# ...
2
โ€‹
3
INSTALLED_APPS = [
4
'my_ra_django_app', # add the name of the app to the configs
5
'django.contrib.admin',
6
'django.contrib.auth',
7
'django.contrib.contenttypes',
8
'django.contrib.sessions',
9
'django.contrib.messages',
10
'django.contrib.staticfiles',
11
]
12
โ€‹
13
# ...
Copied!

Postgres

Django does not come with Postgres by default. It needs to be added.
We must install the Postgres / Python adapter library first:
1
pip3 install psycopg2
Copied!
Then create the database in Postgres:
1
createdb ra_django_db
Copied!
Then set the configurations:
my_ra_django_project/settings.py
1
# ...
2
โ€‹
3
DATABASES = {
4
โ€‹
5
'default': {
6
โ€‹
7
'ENGINE': 'django.db.backends.postgresql_psycopg2',
8
โ€‹
9
'NAME': 'ra_django_db',
10
โ€‹
11
'USER': '<USER_NAME>',
12
โ€‹
13
'PASSWORD': '<PASSWORD>',
14
โ€‹
15
'HOST': 'localhost',
16
โ€‹
17
'PORT': '5432',
18
}
19
}
20
# ...
Copied!
Now we can use Django to alter the database.
11/6/2021: On new M1 Apple products there may be some issues compiling the psycopg2 library on ARM. See this thread: https://github.com/psycopg/psycopg2/issues/1216โ€‹

Migrations

Django knows by default how to create a migration, it does not need specific instructions. We need to create one based on the default settings.
1
python manage.py makemigrations
Copied!
Run the migration:
1
python manage.py migrate
Copied!
Django comes with user functionality builtin. It's best to create a singe default user to begin with.
1
python manage.py createsuperuser
Copied!

Default Tables

Django initialises several standard tables when we run migrations. This is what they look like in psql.
1
Schema | Name | Type | Owner
2
--------+----------------------------+-------+-------
3
public | auth_group | table | akira
4
public | auth_group_permissions | table | akira
5
public | auth_permission | table | akira
6
public | auth_user | table | akira
7
public | auth_user_groups | table | akira
8
public | auth_user_user_permissions | table | akira
9
public | django_admin_log | table | akira
10
public | django_content_type | table | akira
11
public | django_migrations | table | akira
12
public | django_session | table | akira
Copied!
It includes things like the migration tracking table (like Sequelize does) and also the user table and user auth table. We'll see that in the next section.

Models

Django models work very similarly to Sequelize models. They are class instances that allow us to retrieve data from the database without writing SQL statements.
my_ra_django_app/models.py
1
from django.db import models
2
โ€‹
3
class Cat (models.Model):
4
โ€‹
5
name = models.TextField()
6
โ€‹
7
weight = models.IntegerField()
8
โ€‹
9
owner = models.ForeignKey("Owner", on_delete=models.SET_NULL, null=True)
10
โ€‹
11
class Owner(models.Model):
12
โ€‹
13
name = models.TextField()
Copied!
We can run makemigrations to automatically generate the table creation statements, based only on the model code we wrote above.
1
python manage.py makemigrations my_ra_django_app
Copied!
Run the migration:
1
python manage.py migrate my_ra_django_app
Copied!

Further Reading

Seed Data

Seed data works similarly to Sequelize seed data. There are a few choices for formatting the file.

seed.json

1
[
2
{
3
model: 'my_ra_django_app.owner',
4
pk: 1,
5
fields: {
6
name: 'Kai',
7
},
8
},
9
{
10
model: 'my_ra_django_app.owner',
11
pk: 2,
12
fields: {
13
name: 'Alexander',
14
},
15
},
16
{
17
model: 'my_ra_django_app.cat',
18
pk: 1,
19
fields: {
20
name: 'John',
21
weight: 123,
22
owner_id: 1,
23
},
24
},
25
{
26
model: 'my_ra_django_app.cat',
27
pk: 2,
28
fields: {
29
name: 'Paul',
30
weight: 999,
31
owner_id: 1,
32
},
33
},
34
];
Copied!
1
python manage.py loaddata my_ra_django_app/seed.json
Copied!

Further Reading:

Using Models

Now we can use the models in the Django code.
We'll make a new route to test the model:
my_ra_django_app/urls.py
1
from django.urls import path
2
โ€‹
3
from . import views
4
โ€‹
5
urlpatterns = [
6
path("owners/<int:primary_key>/", views.owners, name="owners"),
7
path('', views.index, name='index'),
8
]
Copied!
Now we can use the model in the views file:
my_ra_django_app/views.py
1
from django.shortcuts import render
2
โ€‹
3
from my_ra_django_app.models import Cat, Owner
4
โ€‹
5
from django.http import HttpResponse
6
โ€‹
7
โ€‹
8
def index(request):
9
# send back a text response
10
return HttpResponse("Hello, world. You're at the index.")
11
โ€‹
12
def owners(request, primary_key):
13
โ€‹
14
# get an owner based on the request params
15
owner_obj = Owner.objects.get(pk=primary_key)
16
โ€‹
17
# get the cats owned by this person
18
cat_objs = Cat.objects.filter(owner_id=owner_obj.id)
19
โ€‹
20
# construct a dict we'll use in the template
21
context = {
22
"cats": cat_objs,
23
"owners": owner_obj,
24
}
25
โ€‹
26
return render(request, "owners.html", context)
Copied!

Further Reading

HTML Views

In Django, the files that produce HTML are called templates. First we need to create a directory for them:
1
mkdir my_ra_django_app/templates
Copied!

my_ra_django_app/template/base.html

We can create a partial template for things like the HTML body and head.
1
<!doctype html>
2
<html>
3
<head>
4
<meta charset="utf-8">
5
<meta name="viewport" content="width=device-width, initial-scale=1">
6
<title>RA Wow Django!</title>
7
<link rel="stylesheet" href="https://unpkg.com/[email protected]/css/tachyons.min.css"/>
8
</head>
9
<body>
10
โ€‹
11
<div data-gb-custom-block data-tag="block"></div>
12
โ€‹
13
</body>
14
</html>
Copied!

my_ra_django_app/template/owners.html

Now we can output the data we passed into the render method above:
1
<div data-gb-custom-block data-tag="extends" data-0='base.html'></div>
2
โ€‹
3
<div data-gb-custom-block data-tag="block">
4
โ€‹
5
<div class="mw6 center pa3 sans-serif">
6
โ€‹
7
<h1 class="mb4">Owner: {{ owners.name | linebreaks }}</h1>
8
โ€‹
9
10
โ€‹
11
<div data-gb-custom-block data-tag="for">
12
โ€‹
13
<div class="pa2 mb3 striped--near-white">
14
โ€‹
15
<div class="pl2">
16
โ€‹
17
<p class="mb2">Name: {{ c.name }}</p>
18
โ€‹
19
<p class="mb2">Weight: {{ c.weight }}</p>
20
โ€‹
21
</div>
22
โ€‹
23
</div>
24
โ€‹
25
26
โ€‹
27
</div>
28
โ€‹
29
</div>
30
โ€‹
31
</div>
Copied!

Exercise

Follow the instructions above to create the Django app.

Comfortable

Add other routes to this app:
Route
Method
Description
/cats/:id
GET
get a single cat
/
GET
get all the cats
/cats
POST
create a cat
/owners
POST
create an owner

Further Reading on Forms:

Last modified 2mo ago