20👍
Just realize that you can override the commands just easily as making an app with a command with the same name.
So I create an app and create a file with the same name as runserver, and later on that extend the runserver base class to add a new feature before it runs.
For example, I want to run the command $ compass watch, just before runserver starts and keep it running along runserver execution.
"""
Start $compass watch, command when you do $python manage.py runserver
file: main/management/commands/runserver.py
Add ´main´ app to the last of the installed apps
"""
from optparse import make_option
import os
import subprocess
from django.core.management.base import BaseCommand, CommandError
from django.core.management.commands.runserver import BaseRunserverCommand
from django.conf import settings
class Command(BaseRunserverCommand):
option_list = BaseRunserverCommand.option_list + (
make_option('--adminmedia', dest='admin_media_path', default='',
help='Specifies the directory from which to serve admin media.'),
make_option('--watch', dest='compass_project_path', default=settings.MEDIA_ROOT,
help='Specifies the project directory for compass.'),
)
def inner_run(self, *args, **options):
self.compass_project_path = options.get('compass_project_path', settings.MEDIA_ROOT)
self.stdout.write("Starting the compass watch command for %r\n" % self.compass_project_path)
self.compass_pid = subprocess.Popen(["compass watch %s" % self.compass_project_path],
shell=True,
stdin=subprocess.PIPE,
stdout=self.stdout,
stderr=self.stderr)
self.stdout.write("Compas watch process on %r\n" % self.compass_pid.pid)
super(Command, self).inner_run(*args, **options)
This works just fine.
Look at https://docs.djangoproject.com/en/dev/howto/custom-management-commands/ for more details about django commands
Hope someone find this helpful
7👍
To further expand on @Mario César’s excellent answer, I would like to provide a modern version of his initial 2011 code adapted for Django 1.8+:
Before Django 1.8, management commands were based on the optparse module […] Now that management commands use argparse for argument parsing, all arguments are passed in **options by default […]
Additionally, I would like to point out that the specific command runserver
that was chosen in the question has a slight complication making it both a good and bad example.
Bad example, because the complication is that the command is overridden by Django itself as well. Indeed, Django uses the same method as proposed by Mario: Django overrides it in the staticfiles app (see Django code on github) in order to offer the additional static files options.
Therefore, it is better to override the staticfiles app command rather than the core command, if one uses static. This answers to @ts_pati’s comment too on why there is problem. The Django code of staticfiles is the good example on how to override it, but this time importing the staticfiles in order not to lose that functionality:
from django.contrib.staticfiles.management.commands.runserver import Command as StaticfilesRunserverCommand
class Command(StaticfilesRunserverCommand):
help = "Starts a lightweight Web server for development, serves static files and does some custom fancy stuff."
def add_arguments(self, parser):
super(Command, self).add_arguments(parser)
parser.add_argument('--my-custom-argument', action="...", dest='my_custom_handler', default=True, help='do some stuff in fancy ways')
def get_handler(self, *args, **options):
"""
My fancy stuff function.
"""
handler = super(Command, self).get_handler(*args, **options)
my_custom_handler = options.get('my_custom_handler', True)
# do stuff here
return handler
EDIT: I would also like to add the order of this in INSTALLED_APPS
is apparently important and it has to be before django.contrib.staticfiles
.
1👍
Write your own management command in your app that runs your command and then calls Django’s built-in implementation.
- Django collectstatic no such file or directory
- ALLOWED_HOSTS and Django
- Error loading psycopg2 module: Library not loaded: libpq.5.dylib
- Django form.is_valid() always false