Custom Django Management Commands

Manish Sharma
3 min readJul 26, 2023

--

Custom Django Management Commands

This is part-6 of the DRF/Django Tutorial series.

All tutorials: Part-1 Part-2 Part-3 Part-4 Part-5 Part-6

Django provides manage.py as the command line interface that provides a number of utility commands used while managing project and apps.

For example:

python3 manage.py makemigrations

is used to translate model changes to migrations files.

Similarly

python3 manage.py loaddata <path_to_fixture_file>

is used to load fixture data to database tables.

It is sometimes required to create your own custom commands. Some use cases are:

To execute some task at regular interval using cron.
To execute some admin task using terminal.
To perform clean-up of resources.

Django allows to to create custom commands. In one the App it was required to identify blog-header images that are no longer valid in term of dimensions as per new interface. Earlier users were allowed to upload images of any dimension as blog-header (It was old old story). Now they want to identify all images that are not in valid dimension range (Valid dimensions: minimum: 450, maximum:600).
The task was:

Iterate through blog images one by one
Check dimensions of image
If dimensions are invalid send an email to author to upload a new image.

I have created a simplified version of solution to the problem (for demonstration purposes) by adding two fields to DB table:
dimension_checked: This help us identify if we have checked dimesnion of blog header or not.
has_correct_dimension: If dimensions are correct or not.
After operation has been performed dimension_checked is set to true (so we do not have to read the same image again) and has_correct_dimension is set to either true or false (for future reference).
I will first demonstrate how to create a basic command followed by another command containing implementation discussed above.

How to create a command?

In you app, create a folder management/commands.
Every command is created inside management/commands folder.
The name of file is name of command. so if file name is welcome.py, it is executed as:

$ python3 manage.py welcome

It will print the following:

Welcome to django commands

The command is written as (welcome.py):

All commands are created by creating a class named “Command” by subclassing “BaseCommand”
The handle() method defines command logic.
The help attribute is used to display command help. So if we execute:

python3 manage.py help welcome

The output will display:

Just saying Welcome to django users

Command with arguments

Let’s see another command (sayhello.py):

The function add_arguments() is used to define one or more args to be used.

This command is executed as:

python3 manage.py sayhello "Steves"  

Here “Steves” is value of argument name.

Let’s create the real one !!!

The code is self explanatory, please go through the comments.
The command is executed as:

python3 manage.py checkdim  

And the output is similar to:

File size:  500X400
Email : Hey <User> Please upload a new Image
Width should be between 450px and 600px
Height should be between 450px and 600px

If we want to execute this command as cron job, to be executed every minute, we have to add the following cron entry:

* * * * * /path/to/python3 /path/to/manage.py checkdim 

You can download source code from this repo.
It contains:

imageutils/static/upload folder containing images.
imageutils/fixtures/blogheader.json containing seed data.
imageutils/management/commands folder containing all commands
imageutils/models.py containing model definition.

Make sure to install django, mysqlclient and pillow and update database settings in settings.py.
Installation:

  pip3 install django
pip3 install mysqlclient
pip3 install pillow

Database settings:

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'command_app',
'USER': 'root',
'PASSWORD': 'Pa55word#$',
'HOST': 'localhost',
'PORT': '3306',
}
}

That’s all. Please drop a comment if you have any doubt or query.
Happy coding.

--

--