Yesterday i had to give a short, 30 minutes, introduction to Django and show how to create a small webapplication using Django. These are the my notes to this workshop:
Introduction
Django is a webframework written in Python. It was started in 2003 and in 2005 it was released under the BSD License. In 2008 the Django software foundation took over development of Django. End of 2017 the version 2.0 of Django was released, which was the first Python 3 only release. About every two years there is a LTS release which is supported for at least three years. Famous websites using Django are the website of the Washington Post or the website of the NASA.
Django follows the Model View Controller (MVC) pattern, though in the case of Django it is often described as Model View Template pattern, given that Django doesn’t adhere the MVC pattern completely.
The advantage of a webframework following the MVC pattern is, that the work with data, the presentation of data and the processing of data has only to be dealt with on an abstract layer. This means, one doesn’t have to directly work with database connections, it is not necessary to write SQL statements and also Webforms are handled by Django.
A Django project is started by the command django-admin startproject projectname
. This command creates a folder containgin a Python module and a
management Python script.
user@calculator:~ tree
.
├── manage.py
└── projectname
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
1 directory, 5 files
The management script can be used to handle various configuration tasks, like generating the database structure, creating an admin account or starting the built-in development webserver.
The Python module contains a configuration file which contains settings like the chosen database backend (sqlite by default) and it lets you deactivate the DEBUG mode. The DEBUG mode should be deactivated before moving a Django project to production, because with the activated DEBUG mode, error messages also contain a lot of debugging information about the system. If the DEBUG mode is deactivated, the error messages are replaced with a 404 page.
Another important file is the urls.py
file. It maps paths in the URI to
functionality in the Django project. The last file is the wsgi.py
file, WSGI
is the Web Server Gateway Interface and it is a standard for webservers passing
requests to Python scripts.
Bookmanagement Example
To give a small example what a Django web application could look like, i’ve
created a book management applications. It stores books in a database and lets
you add, view, modify, list and delete book entries. This example was written
with Django 2.1. If you want to try it, you’ll have to 1) install Django, 2)
run ./manage.py migrate
to create the db.sqlite file and populate it with
the database structure and 3) run ./manage.py runserver
to start the
development webserver. You can then access the webapp on
http://localhost:8000
First we have to add an app to our Django project. This app is a simple Python
module and it can be created with the command ./manage.py startapp bookmanagent
(where bookmanagement
is the name of our app). To make this
app known to the Django project, we also have to add the app name to the
list of INSTALLED_APPS
in the settings.py
file.
The first thing to create is a model. Every task in this web application works
on book entries, so we first have to create a model Book
. A model is like an
object in object oriented programming and in Django it is a Python class. We
define a model in the file bookmanagement/models.py
:
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.CharField(max_length=255)
year = models.PositiveSmallIntegerField()
This is a definition of the model Book
with the attributes title
, author
and year
. title
and author
are character fields, the year
attribute is
an integer field. Django contains around 25 different field
types, i.e. for
dates, email addresses or text input.
After defining a model, we have to run ./manage.py makemigrations bookmanagement
and ./manage.py migrate
to create the needed tables in the
database for our model.
To work with our model, the next step is to create views to add, modify,
delete, display and list books. Views are Djangos method to process web
requests. Views go in the bookmanagement/views.py
file. Django comes with a
lot of generic views and we can write Python classes that inherit from those
generic views to implement all the methods we need for the bookmanagement
application:
class BookList(ListView):
model = Book
class BookCreate(CreateView):
model = Book
fields = ['title', 'author', 'year']
success_url = '/books'
class BookDetail(DetailView):
model = Book
class BookUpdate(UpdateView):
model = Book
fields = ['title', 'author', 'year']
success_url = '/books'
class BookDelete(DeleteView):
model = Book
success_url = '/books'
As mentioned before, we use the urls.py
file to map the paths in the URI to
the functionality of the Django project:
path('createbook/', views.BookCreate.as_view(), name='createbook'),
path('book/<int:pk>', views.BookDetail.as_view(), name='bookdetail'),
path('books/', views.BookList.as_view()),
path('deletebook/<int:pk>', views.BookDelete.as_view(), name='deletebook'),
path('updatebook/<int:pk>', views.BookUpdate.as_view(), name='updatebook'),
Now we have the paths, the views to operate on data and the model that
describes the data structure. The only additional piece of the puzzle are
templates. Templates are files that define how a view returns data to a
webbrowser. In our case they contain HTML and some template specific
statements. In most of my Django projects i use a generic body.html
file that
defines the overall structure of the web pages (like including a style sheet or
defining a navigation bar) and all the view-specific templates then inherit the
content of this file (boomanagement/templates/body.html
):
<html>
<head>
<meta charset="utf-8">
<title>Bookmanagement</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body class="bg-light">
<nav class="navbar navbar-dark navbar-expand-md bg-dark mb-4">
<a class="navbar-brand" href="/books">Bookmanagement</a>
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a class="nav-link" href="{% url 'createbook' %}">Add Book</a></li>
</ul>
</nav>
<div class="container">
<div class="jumbotron mt-5">
{% block content %}
{% endblock %}
</div>
</div>
</body>
</html>
The template for the listview
(bookmanagement/templates/bookmanagement/book_list.html
) then only has to
extend this template. The list view passes a list of objects to the template
and in the template we can just iterate through this list and create links for
the details of a book, a link for modifying a book and a link for deleting a
book.
{% extends 'body.html' %}
{% block content %}
<ul>
{% for object in object_list %}
<li>
<a href={% url 'bookdetail' object.pk %}>{{ object.title }}</a>, {{ object.year }}, <a href="{% url 'deletebook' object.id %}">Delete</a>, <a href="{% url 'updatebook' object.id %}">Update</a>
</li>
{% endfor %}
</ul>
{% endblock %}
The template file for the input form
(bookmanagement/templates/bookmanagement/book_form.html
), too, extends the
body.html
template and then simply shows the form that is passed from the
create or update view:
{% extends 'body.html' %}
{% block content %}
<form method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save">
</form>
{% endblock %}
The important thing with form templates is the statement {% csrf_token %}
which includes a token to protect against Cross Site Request
Forgery.
This is all to have a working bookmanagement web application. There is one
other feature of Django, that makes it especially helpful for internal use,
that is the admin interface. Django comes with an admin interface that you can
access on http://localhost:8000/admin
. This can also be used to manage model
objects. If you add
from .models import Book
admin.site.register(Book)
to the file bookmanagement/admin.py
you can manage all your book entries in a
login protected area without having to create views or templates. This can be
useful for very basic internal web applications.
SimpleView
One more thing about views:
As mentioned above, views process web requests. In the views for the
bookmanagement application, we didn’t have to touch any of the functions of
these classes, but if we want, we can override the request processing. In the
following snipplet, i’ve implemented methods for GET
, POST
and DELETE
requests. Django provides us the HttpResonse
object to respond to a request.
As you can see in the get()
method, we can simply pass a string and also give
the desired status code as an argument. The post()
method also simply returns a
string- but to test this method, i had to remove the csrf protection from this
view. This is done in the dispatch()
method using a method_decorator
. Last
but not least there is the delete()
method, which returns a JsonResponse
to
show that Django can also be used to implement APIs. In addition, this method
also sets a header field X-Clacks-Overhead
:
class SimpleView(View):
@method_decorator(csrf_exempt)
def dispatch(self, request):
return super().dispatch(request)
def get(self, request):
return HttpResponse("I'm a teapot!", status=418)
def post(self, request):
return HttpResponse("Going postal!")
def delete(self, request):
response = JsonResponse({'deleted':'foobar', 'useragent': request.META['HTTP_USER_AGENT']})
response['X-Clacks-Overhead'] = "GNU Terry Pratchett"
return response
If we test the views get()
method using httpie:
user@calculator:~ http http://localhost:8000/simpleview/
HTTP/1.1 418 Unknown Status Code
Content-Length: 13
Content-Type: text/html; charset=utf-8
Date: Sat, 02 Mar 2019 16:41:47 GMT
Server: WSGIServer/0.2 CPython/3.7.2+
X-Frame-Options: SAMEORIGIN
I'm a teapot!
The post()
method:
user@calculator:~ http POST http://localhost:8000/simpleview/
HTTP/1.1 200 OK
Content-Length: 13
Content-Type: text/html; charset=utf-8
Date: Sat, 02 Mar 2019 16:42:50 GMT
Server: WSGIServer/0.2 CPython/3.7.2+
X-Frame-Options: SAMEORIGIN
Going postal!
… and the delete()
method:
user@calculator:~ http DELETE http://localhost:8000/simpleview/
HTTP/1.1 200 OK
Content-Length: 50
Content-Type: application/json
Date: Sat, 02 Mar 2019 16:44:01 GMT
Server: WSGIServer/0.2 CPython/3.7.2+
X-Clacks-Overhead: GNU Terry Pratchett
X-Frame-Options: SAMEORIGIN
{
"deleted": "foobar",
"useragent": "HTTPie/0.9.8"
}
You can find the code of the bookmanagement webapplication in my 30mindjango git repository on gitlab.
django python workshop