Advanced Django Development: How to build a professional CMS for any business? (Part #3)

Hossein Vahedi
EngineerX
Published in
3 min readMar 30, 2021

This article is based on the previous one. You can easily follow along by cloning The Official EngineerX Github repository and change directory to part-2:

git clone https://github.com/HsnVahedi/EngineerX
cd EngineerX/backend/part-2

Overview

In the previous article, we dockerized the application. Dockerizing an application makes us able to run it anywhere. We are guaranteed to always have exactly the same environment.

But what about data? Are we able to easily recreate our data?

Currently we don’t have any mechanism to programmatically insert objects into database.

Generating fake objects is the best solution. It can be useful in two places:

  1. generate data for tests: Normally you would like to initialize the database before running tests.
  2. Fill the database for demo: A web application with an empty database cannot be interesting. To represent our project to others, we fill the database with fake objects.

In part #3, we will see how we can generate images programmatically.

Generate image objects:

Follow these steps:

1) Download some images:

Download this folder and put it in WORKDIR/engineerx/.

2) Configure the project to use images:

Set these variables in base.py:

DOWNLOADS_ROOT = os.path.join(MEDIA_ROOT, 'downloads')
IMAGE_DOWNLOADS_DIR = os.path.join(DOWNLOADS_ROOT, 'images')
AVATAR_DOWNLOADS_DIR = os.path.join(DOWNLOADS_ROOT, 'avatars')

Your base.py should now look like this file.

3) Update start.sh:

Add mv -vn downloads/ media/downloads/ to your start.sh. That’s because our django application expects images to be located at /media/downloads/.

Your start.sh should now look like this file.

4) Add a module that generates image objects:

Create a new directory:

mkdir WORKDIR/engineerx/images
mkdir WORKDIR/engineerx/images/modules

Now add fakedata.py to WORKDIR/engineerx/images/modules/ :

import os
import logging
from django.conf import settings
from django.core.files import File
from wagtail.images import get_image_modellogger = logging.getLogger("fake users:")
Image = get_image_model()
def create_dir_if_not_exists(directory):
if not os.path.exists(directory):
os.mkdir(directory)
create_dir_if_not_exists(settings.MEDIA_ROOT)
create_dir_if_not_exists(settings.DOWNLOADS_ROOT)
create_dir_if_not_exists(settings.IMAGE_DOWNLOADS_DIR)
create_dir_if_not_exists(settings.AVATAR_DOWNLOADS_DIR)
def create_wagtail_image(filename):
filepath = os.path.join(settings.IMAGE_DOWNLOADS_DIR, filename)
with open(filepath, "rb") as file:
image_file = File(file)
return Image.objects.create(file=image_file, title=filename)
def create_wagtail_images():
images = []
files = os.listdir(settings.IMAGE_DOWNLOADS_DIR)
for file in files:
images.append(create_wagtail_image(file))
logger.info(
f'Successfully created image: {file}'
)
return images

By calling create_wagtail_images, we can easily create image objects with files located at media/downloads/.

5) Enable wagtail’s feature detection:

Wagtail has this awesome built-in feature to automatically detect the most important part of an image. Please checkout this if you are not familiar with wagtail.

To enable wagtail’s feature detection, set WAGTAILIMAGES_FEATURE_DETECTION_ENABLED = True in base.py.

Yourbase.pyshould now look like this file.

6) Run in Development Environment:

Now it’s time to test our image generation mechanisms.

Build the docker image:

cd WORKDIR/engineerx/
docker build . -t engineerx/backend

Run development environment:

docker run -it -p 8000:8000 engineerx/backend bash

Create a media directory:

mkdir media

Move downloads into media:

mv -vn downloads/ media/downloads/

Run migrations:

python manage.py makemigrations && python manage.py migrate

Open a django shell:

python manage.py shell

Run this script to generate images:

>>> from images.modules import fakedata
>>> fakedata.create_wagtail_images()

Exit from shell:

>>> exit()

Create a superuser:

python manage.py createsuperuser

Run development server:

python manage.py runserver 0.0.0.0:8000

Now you can see the images are created by checking 127.0.0.1:8000/admin/images/

7) Run Production Environment:

Make sure to build the docker image:

cd WORKDIR/engineerx/
docker build . -t engineerx/backend

Start Production Environment:

cd WORKDIR/
export SECRET_KEY=<YOUR_SECRET_KEY>
export POSTGRES_PASSWORD=<YOUR_POSTGRES_PASSWORD>
docker-compose up

Now open another terminal and then open a django shell:

docker-compose exec backend python manage.py shell

Run this script in django shell:

>>> from images.modules import fakedata
>>> fakedata.create_wagtail_images()
>>> exit()

Create a superuser:

docker-compose exec backend python manage.py createsuperuser

Now you can see the images are created by checking 127.0.0.1:8000/admin/images/

Conclusion

In part #3, we have extended the existing project and added a module named fakedata.py to easily generate images.

Just put the appropriate images in WORKDIR/engineerx/ and run a single function:

fakedata.create_wagtail_images()

Next: Generate fake users.

--

--