Custom Django Management Commands

06 Aug, 2021
Prerequisites:  Django Introduction and Installation
Manage.py in Django is a command-line utility that works similar to the django-admin command. The difference is that it points towards the project’s settings.py file. This manage.py utility provides various commands that you must have while working with Django. Some of the most commonly used commands are –
python manage.py startapp
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
Interestingly we can create our own Custom Management Commands to fulfill a wide variety of requirements ranging from interacting with our application using the command line to serve as an interface to execute Cron Jobs. We are going to create a custom Management Command which gives us the stats or metrics of new articles published, comments on those articles on a particular day.
Follow Django Introduction and Installation to setup a virtual environment and install Django
Step 1: Initialize a project by following command
django-admin startproject geeks_site
Step 2: Create an app named blog
python manage.py startapp blog
Step 3: Add your app to the settings.py
In geeks_site/settings.py
Python3
# Application definition  INSTALLED_APPS = [    'django.contrib.admin',    'django.contrib.auth',    'django.contrib.contenttypes',    'django.contrib.sessions',    'django.contrib.messages',    'django.contrib.staticfiles',      'blog',]
Step 4: Create Models named Article and Comment in the blog app
Model Article :
Fields :title: Stores the title of an articlebody: Content of that articlecreated_on: Date and Time on which that article was created
title: Stores the title of an article
body: Content of that article
created_on: Date and Time on which that article was created
Model Comment :
Fields :article:  Article on which comment is createdtext: Actual commentcreated_on: Date and Time on which that article was created
article:  Article on which comment is created
text: Actual comment
created_on: Date and Time on which that article was created
In blog/models.py
Python3
from django.db import models    class Article(models.Model):    title = models.CharField(max_length=200)    body = models.TextField()    created_on = models.DateTimeField(auto_now_add=True)    class Comment(models.Model):    article = models.ForeignKey(Article, on_delete=models.CASCADE)    text = models.CharField(max_length=200)    created_on = models.DateTimeField(auto_now_add=True)
Step 5: Register your model in blog/admin.py so that it shows up in the admin panel.
In blog/admin.py
Python3
from django.contrib import admin from .models import Article, Comment    admin.site.register(Article)admin.site.register(Comment)
Step 6: Now, To migrate all your changes and start the server, run the following commands in your terminal
python manage.py makemigrations
python manage.py migrate
python manage.py runserver
Create a superuser account to log in to the admin panel
python manage.py createsuperuser
Now, Visit the admin panel at http://127.0.0.1:8000/admin/
Create some articles and then some comments :
Now, Let’s start working on the creation of Custom Django Management Commands
Add a management/commands directory to the blog app
Add __init__.py to blog/management and __init__.py + stats.py files to blog/management/commands directory
Note: Django will register a manage.py command for each Python module in that directory whose name doesn’t begin with an underscore
The folder structure of the blog app looks like this :
We will use python manage.py stats to run our custom management command. Now we will configure what actually this command will do.
In stats.py
Python3
from django.core.management.base import BaseCommandfrom django.db.models import Countfrom blog.models import Article, Commentfrom datetime import timedelta, datetimefrom django.utils.timezone import utc    def now():    return datetime.utcnow().replace(tzinfo=utc)    class Command(BaseCommand):    help = 'Displays stats related to Article and Comment models'      def handle(self, *args, **kwargs):        From = now() - timedelta(hours=5)        To = now()          articles_published_in_last_5_hour = Article.objects.filter(            created_on__gt=From, created_on__lte=To).count()        comments_published_per_article = Comment.objects.filter(            created_on__gt=From, created_on__lte=To).values(          'article').annotate(count=Count('article')).order_by()          print("Articles Published in last 5 hours = ",              articles_published_in_last_5_hour)                  print("Comments per Article in last 5 hours")        for data in comments_published_per_article:            print(data)
Understanding the stats.py file
Basically, a Django management command is built from a class named Command which inherits from BaseCommand.
1) help: It tells what actually the command does. Run the following command and see the help
python manage.py stats --help
2) handle(): It handles all the logic which needs to be executed when the command is executed. Let’s understand of code inside handle() method
Here we are concerned about the following two statsNumber of articles which were published in last 5 hoursNumber of  comments created in last 5 hours per article
Number of articles which were published in last 5 hours
Number of  comments created in last 5 hours per article
From: Current time – 5 hours
To: Current Time
articles_published_in_last_5_hour : an integer value
comments_published_per_article :  queryset object or a list of dictionaries
print statements to output data on terminal
Now, Run the following command in your terminal :
python manage.py stats
Output : 
Django uses the argparse module to handle the custom arguments. We need to define a function add_arguments under the command class to handle arguments.
Python3
from django.core.management.base import BaseCommandfrom django.db.models import Countfrom app.models import Article, Commentfrom datetime import timedelta, datetimefrom django.utils.timezone import utc    def now():    return datetime.utcnow().replace(tzinfo=utc)  class Command(BaseCommand):    help = 'Displays stats related to Article and Comment models'      def add_arguments(self, parser):        parser.add_argument('-t', '--time', type=int, help='Articles published in last t hours')      def handle(self, *args, **kwargs):        t = kwargs['time']        if not t:            t=5        From = now() - timedelta(hours=t)        To = now()          articles_published_in_last_t_hour = Article.objects.filter(            created_on__gt=From, created_on__lte=To).count()                  comments_published_per_article = Comment.objects.filter(            created_on__gt=From, created_on__lte=To).values(            'article').annotate(count=Count('article')).order_by()          print(f"Articles Published in last {t} hours = ",              articles_published_in_last_t_hour)          print(f"Comments per Article in last {t} hours")        for data in comments_published_per_article:            print(data)
Output:
Python Django
Python
Writing code in comment?
Please use ide.geeksforgeeks.org,
generate link and share the link here.