Open In App

Custom Django Management Commands

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 –



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.

Getting Started

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




# 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 :

Model Comment :

In blog/models.py




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




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

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




from django.core.management.base import BaseCommand
from django.db.models import Count
from blog.models import Article, Comment
from datetime import timedelta, datetime
from 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

Now, Run the following command in your terminal :

python manage.py stats

Output : 

Adding Arguments

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.




from django.core.management.base import BaseCommand
from django.db.models import Count
from app.models import Article, Comment
from datetime import timedelta, datetime
from 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:


Article Tags :