Creating a simple Dockerized Django Blog App
Creating a simple Dockerized Django Blog App
Docker is an invaluable tool for developers. It allows you to create lightweight, portable development environments called containers that match your production setup. With Docker, you can quickly spin up a dev environment with the tools, dependencies, and configurations you need to build your application. In this comprehensive guide, we’ll go through all the steps to set up a Dockerized development environment for a Django app.
Creating a Django Project
First, let’s create a new Django project. We’ll use the django-admin
command-line utility to create a new project called myproject
:
django-admin startproject myproject
This creates a new directory called myproject
with the following files:
myproject/
├── manage.py
└── myproject
├── __init__.py
├── asgi.py
├── settings.py
├── urls.py
└── wsgi.py
The manage.py
file is a command-line utility that lets you interact with your Django project. You can use it to run development servers, create new apps, and more.
The myproject
directory contains the actual Python package for your project. It’s a Python module that contains all the settings, URLs, and other configurations for your project.
Now we create the ‘requirements.txt’ file:
pip freeze > requirements.txt
Creating a Dockerfile
A Dockerfile defines the steps to assemble your image. Create a new file called Dockerfile
and add:
FROM python:3.8-buster
ENV PYTHONUNBUFFERED=1
WORKDIR /django
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
CMD python manage.py runserver 0.0.0.0:8000
Creating a Docker Compose File
Docker Compose is a tool for defining and running multi-container Docker applications. It uses a YAML file to configure the application’s services, networks, and volumes. We’ll use it to define our Django app and PostgreSQL database.
Create a new file called docker-compose.yml
and add:
version: '3.8'
services:
app:
build: .
volumes:
- .:/django
ports:
- 8000:8000
image: app:django
container_name: django_container
command: python manage.py runserver 0.0.0.0:8000
Building the Docker Image
Now that we have our Dockerfile and docker-compose.yml file, we can build the Docker image. Run the following command:
docker-compose build
This builds the image and tags it as app:django
. You can verify it was built by running:
docker images
Running the Docker Container
Now that we have our image, we can run a container using it. Run the following command:
docker-compose up
This starts the container and runs the Django development server. You can verify it’s running by visiting http://localhost:8000 in your browser.
We can also run the container in detached mode by adding the -d
flag:
docker-compose up -d
This runs the container in the background. You can view the logs by running:
docker-compose logs
Running Django Commands
You can run Django commands inside the container using the docker-compose run
command. For example, to create a new app called blog
, run:
docker-compose run app python manage.py startapp blog
This creates a new directory called blog
with the following files:
blog/
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ └── __init__.py
├── models.py
├── tests.py
└── views.py
You can also run the Django shell by running:
docker-compose run app python manage.py shell
This starts the Django shell where you can interact with your project’s models and database.
Connecting to PostgreSQL
Now that we have our Django app running, let’s connect it to a PostgreSQL database. First, we need to add the psycopg2
package to our requirements.txt
file:
psycopg2==2.8.6
or
pip install psycopg2
Next, we need to update the settings.py
file to use PostgreSQL as the database backend.
By default, Django uses SQLite for the database backend. However, for production use, it’s recommended to use a more robust database such as PostgreSQL. For this tutorial, we’ll use PostgreSQL.
Open the myproject/settings.py
file in your text editor and replace the following code:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': BASE_DIR / 'db.sqlite3',
}
}
With the following code:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'myproject',
'USER': 'myprojectuser',
'PASSWORD': 'mypassword',
'HOST': 'db',
'PORT': 5432,
}
}
This will configure Django to use a PostgreSQL database named myproject
with a username of myprojectuser
and a password of mypassword
.
Next, we need to update the docker-compose.yml
file to include a PostgreSQL service. Add the following code:
version: '3.8'
services:
app:
build: .
volumes:
- .:/django
ports:
- 8000:8000
image: app:django
container_name: django_container
command: python manage.py runserver
db:
image: postgres:13.1
volumes:
- postgres_data:/var/lib/postgresql/data/
environment:
- POSTGRES_DB=myproject
- POSTGRES_USER=myprojectuser
- POSTGRES_PASSWORD=mypassword
volumes:
postgres_data:
This code does the following:
- Defines two services:
db
andapp
- Uses the official PostgreSQL Docker image for the
db
service - Sets the environment variables for the
db
service to configure the PostgreSQL database - Maps port 5432 on the host to port 5432 in the container for the
db
service - Builds the Docker image for the
app
service using theDockerfile
in the current directory - Runs the
python3 manage.py runserver
command to start the Django development server - Maps port 8000 on the host to port 8000 in the container for the
app
service - Specifies that the
app
service depends on thedb
service
Now that we’ve updated the docker-compose.yml
file, we need to rebuild the Docker image and start the container. Run the following command:
docker-compose up -d --build
This rebuilds the Docker image and starts the container in detached mode. You can verify it’s running by visiting http://localhost:8000 in your browser.
Next, we need to create the database tables by running the following command:
docker-compose run app python manage.py migrate
This creates the database tables for the default Django models, including the auth
and admin
models.
Creating an Admin User
Next, we need to create an admin user so we can log in to the Django admin dashboard. Run the following command:
docker-compose run app python manage.py createsuperuser
You’ll be prompted to enter a username, email, and password for the admin user.
Adding a Blog Model
Now that we have our Django app running and connected to a PostgreSQL database, let’s add a blog model. We’ll use this model to create blog posts.
Open the blog/models.py
file in your text editor and add the following code:
from django.db import models
from django.contrib.auth.models import User
class Post(models.Model):
title = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, unique=True)
author = models.ForeignKey(User, on_delete=models.CASCADE)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('-created',)
def __str__(self):
return self.title
This defines a Post
model with the following fields:
title
- The title of the blog postslug
- The slug of the blog post. This is used in the URL of the blog postauthor
- The author of the blog post. This is a foreign key to theUser
modelbody
- The body of the blog postcreated
- The date and time the blog post was createdupdated
- The date and time the blog post was last updated
Next, we need to create a database migration for the Post
model. Run the following command:
docker-compose run app python manage.py makemigrations blog
This creates a database migration for the blog
app. Next, we need to apply the migration to the database by running the following command:
docker-compose run app python manage.py migrate
This creates the Post
model in the database.
Registering the Blog Model in the Admin Dashboard
Next, we need to register the Post
model in the admin dashboard. Open the blog/admin.py
file in your text editor and add the following code:
from django.contrib import admin
from .models import Post
@admin.register(Post)
class PostAdmin(admin.ModelAdmin):
list_display = ('title', 'slug', 'author', 'created', 'updated')
prepopulated_fields = {'slug': ('title',)}
This registers the Post
model in the admin dashboard and specifies which fields are displayed in the list of blog posts.
Next, we can test the admin dashboard by creating a blog post visitin http://localhost:8000/admin in your browser. Log in using the admin user you created earlier.
Next, click on the + Add button next to Posts. Enter a title, slug, author, and body for the blog post and click Save. You should see the blog post listed on the next page.
Creating a Homepage
Now that we have a blog model, let’s create a homepage that lists all the blog posts. Open the blog/views.py
file in your text editor and replace the following code:
from django.shortcuts import render
# Create your views here.
With the following code:
from django.views.generic import ListView
from .models import Post
class HomePageView(ListView):
model = Post
template_name = 'home.html'
This defines a HomePageView
class that extends Django’s ListView
class. This class will query the database for all the blog posts and render them using the home.html
template.
Next, we need to create the home.html
template. Create a new directory named templates
in the blog
directory. Then, create a new file named home.html
in the templates
directory and add the following code:
{% extends 'base.html' %} {% block title %}Blog{% endblock %} {% block content %} {% for post in
object_list %}
<h2><a href="{% url 'post_detail' post.slug %}">{{ post.title }}</a></h2>
<p>{{ post.body|truncatewords:30 }}</p>
<p>Created: {{ post.created }}</p>
<p>Updated: {{ post.updated }}</p>
<hr />
{% endfor %} {% endblock %}
This extends the base.html
template and displays the title, body, created date, and updated date for each blog post.
Next, we need to create a URL route for the homepage. Open the blog/urls.py
file in your text editor and add the following code:
from django.urls import path
from .views import HomePageView
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
]
This defines a URL route for the homepage that renders the HomePageView
class.
Next, we need to update the mysite/urls.py
file to include the URL routes for the blog
app. Open the mysite/urls.py
file in your text editor and replace the following code:
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
With the following code:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
This includes the URL routes for the blog
app.
Next, we need to create a base template that the home.html
template can extend. Create a new file named base.html
in the templates
directory and add the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>{% block title %}{% endblock %}</title>
</head>
<body>
{% block content %} {% endblock %}
</body>
</html>
This defines a base template that the home.html
template can extend.
Creating a Blog Post Detail Page
Next, we need to create a URL route for the blog post detail page. Open the blog/urls.py
file in your text editor and add the following code:
from django.urls import path
from .views import HomePageView, PostDetailView
urlpatterns = [
path('', HomePageView.as_view(), name='home'),
path('<slug:slug>/', PostDetailView.as_view(), name='post_detail'),
]
This defines a URL route for the blog post detail page that renders the PostDetailView
class.
Next, we need to create the PostDetailView
class. Open the blog/views.py
file in your text editor and add the following code:
from django.views.generic import ListView, DetailView
from .models import Post
class HomePageView(ListView):
model = Post
template_name = 'home.html'
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
This defines a PostDetailView
class that extends Django’s DetailView
class. This class will query the database for a single blog post and render it using the post_detail.html
template.
Next, we need to create the post_detail.html
template. Create a new file named post_detail.html
in the templates
directory and add the following code:
{% extends 'base.html' %} {% block title %}{{ object.title }}{% endblock %} {% block content %}
<h2>{{ object.title }}</h2>
<p>{{ object.body }}</p>
<p>Created: {{ object.created }}</p>
<p>Updated: {{ object.updated }}</p>
{% endblock %}
This extends the base.html
template and displays the title, body, created date, and updated date for a single blog post.
Conclusion
That’s it! You’ve successfully created a blog app with Django in Docker.
Happy coding!