2011-07-11 14 views
15

Quiero ejecutar un comando justo antes de que se inicie el comando django.¿Hay alguna manera de agregar funciones a un comando django existente?

Por ejemplo:

$ python manage.py runserver 
Validating models... 

0 errors found 
Django version 1.3, using settings 'creat1va.settings' 
Development server is running at http://127.0.0.1:8000/ 
Quit the server with CONTROL-C. 
(started some command in the background) 
[10/Jul/2011 21:50:26] "GET/HTTP/1.1" 200 1611 
[10/Jul/2011 21:50:26] "GET /assets/css/master.css HTTP/1.1" 404 1783 
[10/Jul/2011 21:50:26] "GET /assets/images/misc/logo.png HTTP/1.1" 404 1801 
[10/Jul/2011 21:50:26] "GET /assets/images/icons/bo.gif HTTP/1.1" 404 1798 
[10/Jul/2011 21:50:28] (My background process) "Some nice Feedback" 

La idea principal es iniciar un proceso en segundo plano, y la salida de la explotación forestal.

¿Hay alguna manera de lograr esto, sin hackear las fuentes django?

Respuesta

16

Simplemente tenga en cuenta que puede anular los comandos simplemente haciendo una aplicación con un comando con el mismo nombre.

Así que creo una aplicación y creo un archivo con el mismo nombre que runserver, y más adelante extiendo la clase base de runserver para agregar una nueva característica antes de que se ejecute.

Por ejemplo, quiero ejecutar el comando $ compás reloj, justo antes de que se inicie runserver y mantenerlo ejecutándose a lo largo de la ejecución de runserver.

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

Esto funciona bien.

Mira https://docs.djangoproject.com/en/dev/howto/custom-management-commands/ para más detalles acerca de Django comandos

espero que alguien ha resultado útil

+1

¿Tuvo algún problema con estática usando este comando? No sé por qué, pero incluso con la función inner_run vacía (solo con call_fun inner_run), statics no se está cargando. Tengo 404 para todos. –

+0

@ts_pati mira mi respuesta a continuación sobre lo que está pasando con los archivos estáticos. – Wtower

+1

Nota de [django 1.9 documentos] (https://docs.djangoproject.com/en/1.9/ref/settings/): Cuando varias aplicaciones proporcionan diferentes versiones del mismo recurso (plantilla, archivo estático, comando de gestión, traducción), la aplicación que figura primero en INSTALLED_APPS tiene prioridad. Editar: @Wtower menciona esto en su respuesta a continuación – msnider

1

Escriba su propio comando de administración en su aplicación que ejecuta su comando y luego llama a la implementación integrada de Django.

+1

Gracias, miro los comandos del núcleo django, hice un código para hacer eso, estoy publicando como las respuestas. Gracias de nuevo :-) –

3

para ampliar aún más el excelente respuesta de @Mario César, me gustaría ofrecer una versión moderna de la inicial de su código de 2011 adaptada para Django 1.8+:

Antes de Django 1.8, los comandos de administración se basaron en el módulo optparse [...] Ahora que los comandos de administración usan argparse de análisis de argumentos, todos los argumentos se pasan en las opciones por defecto ** [. ..]

Source

Además, me gustaría señalar que el comando específico runserver que fue elegida en la pregunta tiene una ligera complicación por lo que es tanto un ejemplo bueno y malo.

Mal ejemplo, porque la complicación es que el comando también es anulado por Django. De hecho, Django utiliza el mismo método propuesto por Mario: Django lo anula en la aplicación staticfiles (ver Django code on github) para ofrecer las opciones adicionales de archivos estáticos.

Por lo tanto, es mejor anular el comando de la aplicación staticfiles en lugar del comando central, si se usa estático. Esto también responde al comentario de @ ts_pati sobre por qué hay un problema. El código de Django de staticfiles es el buen ejemplo de cómo anularlo, pero esta vez la importación de los staticfiles con el fin de no perder esa funcionalidad:

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: También me gustaría añadir el orden de esto en INSTALLED_APPS es aparentemente importante y tiene que ser anterior al django.contrib.staticfiles.

Cuestiones relacionadas