post cover

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 and app
  • 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 the Dockerfile 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 the db 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 post
  • slug - The slug of the blog post. This is used in the URL of the blog post
  • author - The author of the blog post. This is a foreign key to the User model
  • body - The body of the blog post
  • created - The date and time the blog post was created
  • updated - 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!