Open In App

Custom Django Management Commands

Last Updated : 06 Aug, 2021
Improve
Improve
Like Article
Like
Save
Share
Report

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.

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

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

  • Here we are concerned about the following two stats
    • 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 : 

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.

Python3




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:



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads