Writing Custom Management Commands in Django

Rafael Salimov
Analytics Vidhya
Published in
3 min readMar 7, 2021

--

Image source: here

Sometimes we need to execute one-off tasks. For example: change something from the database automatically, send reports or notifications, schedule some tasks, and so on. If you want to call these commands whenever you want then management commands are the best choice. You can even use management commands as workers in production. Django itself has several commands such as migrate, makemigrations, runserver, and so on. Now I will show you have to write your own management command. Let’s begin!

Project Structure

I assume you already have a ready Django project called “my_project” and an app called “my_app”. Go inside this app, and create parent directory “management” and child directory commands. Now your project structure should look like that:

Ignore __pycache__ directory

Command

Create a python file with the name “my_command.py” inside the commands directory:

Let’s open my_command.py and create simple command to check whether the command works or not. To write a command we have to define a Command class that inherits from BaseCommand class. To do that let’s import BaseCommand and CommandError classes to handle errors, too.

from django.core.management.base import BaseCommand, CommandErrorclass Command(BaseCommand):
help = "Command to print a text"
def handle(self, *args, **options):
try:
print('Command is executed')
except Exception as e:
raise CommandError(e)

You can define a variable help to explain what is the purpose of the command. The function handle will execute our command. The command is done, let’s check it. Open the terminal and call it with the following command:

py manage.py my_command

You will see the output: Command is executed

We learned how to write a simple command, and now we can execute more advanced commands such as sending reports, emails, and so on. Let’s do it:

1. Create a Report model:

Go to my_app.models and create a model:

from django.db import modelsclass Report(models.Model):
receiver = models.EmailField()
content = models.TextField(max_length=500)
sent = models.BooleanField(default=False)
created_date = models.DateField(auto_now_add=True)

def __str__(self):
return self.receiver

2. Write a Command:

Back to my_command.py and change it in this way:

from django.core.management.base import BaseCommand, CommandError
from django.core.mail import EmailMessage
from my_app.models import Report
class Command(BaseCommand):
help = "Execute to send all unsent reports"
def handle(self, *args, **options):
try:
reports = Report.objects.filter(sent=False)
if reports.exists():
for report in reports:
subject = 'Report'
receiver = report.receiver
content = report.content
new_email = EmailMessage(
subject, content,
'youremailaddress', [receiver])
new_email.send(fail_silently=False)
report.sent = True
report.save()

except Exception as e:
raise CommandError(e)

In this example, we took all unsent reports and send them.

In some cases, you may want to send a specific report. For that purpose, we will add the add_arguments function to the Command class. Now the class should look like that:

from django.core.management.base import BaseCommand, CommandError
from django.core.mail import EmailMessage
from my_app.models import Report
class Command(BaseCommand):
help = "Execute to send all unsent reports"
def add_arguments(self, parser):
parser.add_argument('report_ids', nargs='+', type=int)
def handle(self, *args, **options):
for id in options['report_ids']:
try:
report = Report.objects.get(id=id)

except Report.DoesnNotExist:
raise CommandError('Report doesn not exist')

subject = 'Report'
receiver = report.receiver
content = report.content
new_email = EmailMessage(
subject, content,
'youremailaddress', [receiver])
new_email.send(fail_silently=False)
report.sent = True
report.save()

The first attribute inside add_aruments shows us how we can access the ids in the handle function.

Call this command with a specific id:

py manage.py my_command <report_ids>

You can send one id or even a list of ids

Conclusion

At the end of the tutorial, we learned how to custom management commands in different ways and execute them. Write below if you have any questions

Thanks for reading. Stay tuned for more ✌

--

--