Basic tutorial for Django with Docker[Python3]

Django is the most famous web framework for Python.
In this article, I would like to share basic tutorial of Django for beginner.

👽 Create Project Directory


🎉 Create requirements.txt

Create requirements.txt:


You will install following libraries:

🍄 Dockerfile

Add Dockerfile:

FROM python

# Environment variable

# update apt-get
RUN apt-get update -y && apt-get upgrade -y

# install libraries
RUN apt-get install -y groff-base

# change work directory
RUN mkdir -p /app

ADD requirements.txt /app/
RUN pip install -r requirements.txt


CMD [" runserver$PORT"]

🏈 docker-compose.yml

Add docker-compose.yml:

version: '3.5'

build: .
tty: true
stdin_open: true
restart: always
- "8000"
- "8000:8000"
- db
working_dir: /app
- .:/app
- ./ssh:/root/.ssh
command: ./ runserver

image: postgres:10.4

🐝 Start Docker container

Start a Docker container and use bash in the container by the following terminal commands:

docker-compose up -d
docker-compose exec app /bin/bash

If you want to stop the docker containers, please execute docker-compose down.

🐠 Create Django project

In docker container, please execute it: startproject myapp
cd myapp

😸 Create Application in the Project

Create new application in your project:

python startapp cms

🍮 Initial configuration

python migrate

🐡 Start server

python runserver

After then, please execute open http://$(docker-machine ip):8000/ in your local terminal(not docker container).

🚌 Configuration for project

Configure myapp/

ALLOWED_HOSTS = ['DOCKER_MACHINE_IP'] # Please add docker machine ip

'cms', # your application
'bootstrap4', # django-bootstrap4

🎃 Create superuser and logging into admin

# Input user id and password
python createsuperuser

You can logging into admin by open http://$(docker-machine ip):8000/admin with the above user id and password

🐞 Admin configuration

Modify cms/

from django.contrib import admin
from cms.models import Book, Impression

class BookAdmin(admin.ModelAdmin):
list_display = ('id', 'name', 'publisher', 'page',)
list_display_links = ('id', 'name',)

class ImpressionAdmin(admin.ModelAdmin):
list_display = ('id', 'comment',)
list_display_links = ('id', 'comment',)
raw_id_fields = ('book',), BookAdmin), ImpressionAdmin)

😎 Model

Modify cms/

from django.db import models

class Book(models.Model):
name = models.CharField('title', max_length=255)
publisher = models.CharField('publisher', max_length=255, blank=True)
page = models.IntegerField('page_number', blank=True, default=0)

def __str__(self):

class Impression(models.Model):
book = models.ForeignKey(Book, verbose_name='book', related_name='impressions', on_delete=models.CASCADE)
comment = models.TextField('comment', blank=True)

def __str__(self):
return self.comment

🗻 Execute migration

# Create migration file
python makemigrations cms

# Confirm SQL of the migration
python sqlmigrate cms 0001

# Execute the Migration
python migrate cms

🐹 Views

Modify cms/

from django.shortcuts import render, get_object_or_404, redirect

from cms.models import Book
from cms.forms import BookForm

def book_list(request):
books = Book.objects.all().order_by('id')
return render(request,
{'books': books})

def book_edit(request, book_id=None):
if book_id:
book = get_object_or_404(Book, pk=book_id)
book = Book()

if request.method == 'POST':
form = BookForm(request.POST, instance=book)
if form.is_valid():
book =
return redirect('cms:book_list')
form = BookForm(instance=book)

return render(request, 'cms/book_edit.html', dict(form=form, book_id=book_id))

def book_del(request, book_id):
book = get_object_or_404(Book, pk=book_id)
return redirect('cms:book_list')

Create cms/templates/cms/base.html:

{% load i18n static %}
<!DOCTYPE html>{% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="">
{% block extra_css %}{% endblock %}
<title>{% block title %}My books{% endblock %}</title>
<div class="container">
{% block content %}
{{ content }}
{% endblock %}
<script src=""></script>
<script src=""></script>
{% block extra_js %}{% endblock %}

Create cms/templates/cms/book_list.html:

{% extends "cms/base.html" %}

{% block title %}List of books{% endblock title %}

{% block content %}
<h4 class="mt-4 border-bottom">List of books</h4>
<a href="{% url 'cms:book_add' %}" class="btn btn-primary btn-sm my-3">Add</a>
<table class="table table-striped table-bordered">
<th scope="col">ID</th>
<th scope="col">Title</th>
<th scope="col">Publisher</th>
<th scope="col">Page number</th>
<th scope="col">Control</th>
{% for book in books %}
<th scope="row">{{ }}</th>
<td>{{ }}</td>
<td>{{ book.publisher }}</td>
<td>{{ }}</td>
<a href="{% url 'cms:book_mod' %}" class="btn btn-outline-primary btn-sm">Edit</a>
<button class="btn btn-outline-danger btn-sm del_confirm" data-toggle="modal" data-target="#deleteModal" data-pk="{{ }}" data-url="{% url 'cms:book_del' %}">Delete</button>
{% endfor %}

{# Confirmation dialog #}
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="deleteModalLabel">Confirmation</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<div class="modal-body">
<p>Delete ID: <span id="del_pk"></span>?</p>
<div class="modal-footer">
<a href="#" class="btn btn-primary" id="del_url">OK</a>
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
{% endblock content %}

{% block extra_js %}
$(function() {
$('.del_confirm').on('click', function () {
$('#del_url').attr('href', $(this).data("url"));
{% endblock %}

Create cms/templates/cms/book_edit.html:

{% extends "cms/base.html" %}
{% load bootstrap4 %}

{% block title %}Edit book{% endblock title %}

{% block content %}
<h4 class="mt-4 mb-5 border-bottom">Edit book</h4>
{% if book_id %}
<form action="{% url 'cms:book_mod' book_id=book_id %}" method="post">
{% else %}
<form action="{% url 'cms:book_add' %}" method="post">
{% endif %}
{% csrf_token %}
{% bootstrap_form form layout='horizontal' %}
<div class="form-group row">
<div class="offset-md-3 col-md-9">
<button type="submit" class="btn btn-primary">Send</button>
<a href="{% url 'cms:book_list' %}" class="btn btn-secondary btn-sm">Back</a>
{% endblock content %}

🎳 Form

Create cms/

from django.forms import ModelForm
from cms.models import Book

class BookForm(ModelForm):
class Meta:
model = Book
fields = ('name', 'publisher', 'page',)

🗽 URL Routing

Create cms/

from django.urls import path
from cms import views

app_name = 'cms'
urlpatterns = [
# Book
path('book/', views.book_list, name='book_list'), # list
path('book/add/', views.book_edit, name='book_add'), # create
path('book/mod/<int:book_id>/', views.book_edit, name='book_mod'), # edit
path('book/del/<int:book_id>/', views.book_del, name='book_del'), # delete

Modify admin/

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
path('cms/', include('cms.urls')),

😼 Confirmation CRUD pages

http://$(docker-machine ip):8000/cms/book/
http://$(docker-machine ip):8000/cms/book/add/
http://$(docker-machine ip):8000/cms/book/mod/1/
http://$(docker-machine ip):8000/cms/book/del/2/

🚕 References

🖥 Recommended VPS Service

VULTR provides high performance cloud compute environment for you. Vultr has 15 data-centers strategically placed around the globe, you can use a VPS with 512 MB memory for just $ 2.5 / month ($ 0.004 / hour). In addition, Vultr is up to 4 times faster than the competition, so please check it => Check Benchmark Results!!