Custom Commands in Django
Tags: django, beginners, python, tutorial
Published: 2024-01-25 17:28:34

Hello there! We are going to learn how to write simple custom Django commands. I will break down this lesson into 3 sections;

* Introduction
* Setting up the commands
* Calling the commands


## **Introduction**
* Create a generic Django project called `resource_center`.
* Make migrations and migrate your database.
* Create a Django app called `books`. Register this app in `settings.py`
* In your `book/models.py` create a model `Book` as shown below;

```python
# books/models.py

from django import models

class Book(models.Model):
    name = models.CharField(max_length=50)
    author = models.CharField(max_length=20)

```
* Make migrations and migrate your database.


## **Setting Up Commands**
Django convention dictates that custom commands have to live inside the `project/app/management/commands` directory of your project. In this case, this will be `resource_center/management/commands`.
Navigate to your `books` folder and create a folder named `management`. Create a subfolder called `commands`.
Create a file inside the `commands` folder and name it `books_creator.py`.
Add the following code;

```python
# resource_center/books/management/commands/books_creator.py
from django.core.management.base import BaseCommand
from resource_center.books.models import Book


class Command(BaseCommand):
    help = "Create initial data for the project"

    def add_arguments(self, parser):
        # Positional arguments
        parser.add_argument("count", help="Any number", type=int)

        # Named (optional) arguments
        parser.add_argument(
            "--delete",
            help="Delete books instead of creating them",
        )

    def handle(self, *args, **kwargs):
        count = kwargs.get("count")
        print(f"The current count is {count}")
        if kwargs["delete"]:
            Book.objects.all().delete()
        else:
            Book.objects.get_or_create(
                name="The Lord of the Rings",
                author="J.R.R. Tolkien"
            )
            Book.objects.get_or_create(
                name="The Hobbit",
                author="J.R.R. Tolkien"
            )


```

Our class `Command` inherits from Django's `BaseCommand`.
The class variable `help` describes what the custom command aims to achieve, more like the `help_text` in your model fields.

The method `add_arguments` is used to instruct the command to expect arguments which may be optional.

The method `handle` handles (pun intended 😅) your logic.

## **Calling the commands**
To call your commands, call them in the following format;
`python manage.py <custom_command_file_name>`. Do not include the file's `.py` extension.
In this case, our command will be called as

`python manage.py books_creator <count>`

The `count` is any number of your choice. This is a positional argument that we can not ignore. If ignored, it will raise the following error; `manage.py books_creator: error: the following arguments are required: count`.

The command with our `count` positional argument will be as follows;
`python manage.py books_creator 16`

If you add the optional named arguments, you get a command like this;
`python manage.py books_creator 16 --delete=true`


That's it!