30minutes Django introduction

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