When developing a Django application you will eventually find useful to have some command-line admin commands. There are zillions of reasons you may need them. From generating reports to clear cache data from your app.
In this post we are going to see step by step how to create a Django admin command and how to use it.
Suppose this scenario: your Django app makes use of the cache framework in order to cache the stuff you need and sometimes you may need to clear it in a quick fashion.
Admin commands to the rescue here! Actually it’s quite easy to do it. First of all you need to create this folder and file structure inside one of your existing apps:
example/
└── management
│ ├── commands
│ │ ├── clearcache.py
│ │ └── __init__.py
│ └── __init__.py
├── cacheutils.py
├── ...
...
We have an example
app and inside it we have a management folder (which is a python package as of the __init__.py file) and one level deeper another python package named commands
.
It is inside this second package where you place the commands you want to use with the app. In this case we have created a clearcache.py
file which we will be able to use by issuing the command python manage.py clearcache
. This is how it looks like when running ./manage.py
without arguments and after placing example
as an INSTALLED_APPS
.
(easydevmixin_ve)vagrant@vagrant-ubuntu-trusty-64:/vagrant/easydevmixin_dev/src$ ./manage.py
Type 'manage.py help <subcommand>' for help on a specific subcommand.
Available subcommands:
...
[example]
clearcache
...
Sharp-eyed people will notice a cacheutils.py
. This is just for using in the example. It just contains dummy functions. The whole code for this module is:
1 2 3 4 5 6 | def clear_whole_cache():
print("Hey, the whole cache is cleared!")
def clear_partial_cache():
print("Hey, partial cache is cleared!")
|
Developing the command
Now that we have the structure, we need to tell the command what we want it to do. In order for a Django admin command to work, you must create a class named Command
extending the BaseCommand
class placed in django.core.management.base
. At the same time, this class will have to implement, at its minimum, the method handle(self, \*args, \*\*options)
Here is how to do it:
from django.core.management.base import BaseCommand, CommandError
class Command(BaseCommand):
def handle(self, *args, **options):
pass
This is a base skeleton for our command. Obviously it won’t do anything, but it won’t crash neither. If the only thing we would like to do is just clear all the cache, we can import our cacheutils.py
module and just use it inside our handle
method.
from django.core.management.base import BaseCommand, CommandError
from example import cacheutils
class Command(BaseCommand):
def handle(self, *args, **options):
try:
cacheutils.clear_whole_cache()
except Exception as e:
raise CommandError("An error has occurred: {}".format(e))
And that would be all… if we just want to clear all our cache! What if we want to clear the cache, but just partially?
Passing parameters
We can add parameters to our django-admin commands. Currently (as of Django 1.8) the argparse
library is used. The ability to add commands comes with the addition of the method add\_arguments(*parser*)
. Suppose, as we said before, we just want to clear the cache partially. The way to do that will depend on the use case. We could add the following:
def add_arguments(self, parser):
# This is an optional argument
parser.add_argument(
'--partial', # argument flag
action='store_true', # action to take, stores true if present
dest='partial', # argument name
default=False, # it is false by default
help="Clears the cache partially" # a help message
)
You can also add positional (mandatory) arguments. For instance, if you would like to get rid of some specific elements you coud pass along a positional argument the ids of those elements so the command would delete them. Take a look at the Futher information below to find mor information on that.
Once we have implemented the add_arguments(parser)
method we can query the parameters on the handle(*args, **options)
by asking to **options
:
if options['partial']:
cacheutils.clear_partial_cache()
else:
cacheutils.clear_whole_cache()
And that’s all! Here's the whole code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | from django.core.management.base import BaseCommand, CommandError
from example import cacheutils
class Command(BaseCommand):
def add_arguments(self, parser):
# This is an optional argument
parser.add_argument(
'--partial', # argument flag
action='store_true', # action to take, stores true if present
dest='partial', # argument name
default=False, # it is false by default
help="Clears the cache partially" # a help message
)
def handle(self, *args, **options):
try:
if options['partial']:
cacheutils.clear_partial_cache()
else:
cacheutils.clear_whole_cache()
except Exception as e:
raise CommandError("An error has occurred: {}".format(e))
self.stdout.write("Command executed successfully")
|
And here are some actual outputs from the code:
(easydevmixin_ve)vagrant@vagrant-ubuntu-trusty-64:/vagrant/easydevmixin_dev/src$ ./manage.py clearcache --help
usage: manage.py clearcache [-h] [--version] [-v {0,1,2,3}]
[--settings SETTINGS] [--pythonpath PYTHONPATH]
...
--partial Clears the cache partially
(easydevmixin_ve)vagrant@vagrant-ubuntu-trusty-64:/vagrant/easydevmixin_dev/src$ ./manage.py clearcache
Hey, the whole cache is cleared!
Command executed successfully
(easydevmixin_ve)vagrant@vagrant-ubuntu-trusty-64:/vagrant/easydevmixin_dev/src$ ./manage.py clearcache --partial
Hey, partial cache is cleared!
Command executed successfully
Further information
Take a look at the excellent Django documentation on Writing custom django-admin commands. I find specially useful the section on BaseCommand subclasses. For the argparse
library take a look at 16.4. argparse — Parser for command-line options, arguments and sub-commands