2014-11-13 10 views
9

Ho cercato di reindirizzare l'output standard di un comando di Django personalizzato utilizzando questo pezzo di codice:Redirect management.call_command() stdout in un file

from django.core.management.base import BaseCommand 
from django.core import management 


class Command(BaseCommand): 

    def handle(self, *args, **options): 
     f = open('/tmp/output', 'r+') 
     management.call_command('basequery', 'list', 'log', stdout=f) 
     f.close() 

Tuttavia, quando chiamo questo da gestire. l'output standard appare sulla console e il file/tmp/output viene creato ma vuoto.

Ecco il Django documentation di quello che sto cercando di fare

+0

Sto forse supponendo perché 'open ('/ tmp/output', 'r +')' apre il file solo per _reading_, ma devi essere in grado di scriverci – Anentropic

+0

@Anentropic 'r +' significa leggere e Scrivi. Ho già provato con 'w' e ottengo lo stesso risultato – Phob1a

+0

oops, hai ragione!:) – Anentropic

risposta

5

Questa domanda è un anno ormai, ma io sono il 99% certo di avere la risposta corretta che gli altri 3 hanno mancato. Quindi lo lascio qui per aiutare i futuri lettori:

Il tuo comando probabilmente usa solo print direttamente. Per essere in grado di catturare o reindirizzare le stampe in un comando di gestione, ti consigliamo di utilizzare il self.stdout maniglia della istanza di comando:

from __future__ import print_function 

class Command(BaseCommand): 

    def handle(self, *args, **options): 
     # incorrect way to print in a management command: 
     print('This line will go to the terminal') 

     # correct ways to print in a management command: 
     print('This line will go into the StringIO', file=self.stdout) 
     self.stdout.write('This will also go into the StringIO') 

Se proprio non è possibile modificare le istruzioni di stampa buggy del comando (è la codice nel comando 'basequery' in errore nell'esempio), quindi è possibile utilizzare un gestore di contesto per temporaneamente reindirizzare stdout per acquisire tale output. È importante ripristinare il vecchio stdout dopo il reindirizzamento. Vedi contextlib.redirect_stdout.

+1

O semplicemente usa self.stdout.write ('...') – tbm

0

Sto usando questo per reindirizzare l'output su file

f = open('/path/to/file', 'w') 
    buf = StringIO() 
    call_command('compile_game_data', 'kingdom', indent=4, stdout=buf) 
    buf.seek(0) 
    f.write(buf.read()) 
    f.close() 
+1

Ho provato il tuo metodo ma ottengo lo stesso risultato. La riga di comando continua a stampare lo stdout e il metodo StringIO .read() dopo aver fatto .seek (0) non restituisce nulla. Lo stesso risultato del passaggio stdout = f. – Phob1a

+0

È possibile fornire il codice effettivo che si utilizza con StringIO? – Igor

+0

sicuro. L'ho postato come risposta qui sotto. – Phob1a

-2

ho provato approssimazione di Igor utilizzando il seguente codice:

class Command(BaseCommand): 

    def handle(self, *args, **options): 
     f = open('/tmp/output', 'w+') 
     out = StringIO() 
     management.call_command('basequery', 'list', 'log', stdout=out) 
     out.seek(0) 
     f.write(out.read()) 
     f.close() 

Ho ottenuto lo stesso risultato difficile: file vuoto e stdout visualizzati nella console. Forse perché sto chiamando i comandi django da un comando django?

In ogni caso, sono riuscito a risolvere il problema in questo modo:

sys.stdout = open('/tmp/output', 'w+') 
    management.call_command('basequery', 'list', 'log') 
    sys.stdout.close() 

So che è una soluzione brutta, ma è l'unico modo che ho fatto funzionare.

+1

Interrompe lo stdout, se si stampa qualcosa dopo questo codice si ottiene 'ValoreErrore: operazione I/O su file chiuso. – Mark

+0

non è possibile ripararlo salvando' sys.stdout' su una variabile temporanea e ripristinandola dopo? – spectras

2

Se si ha il controllo sul codice del comando di gestione, è necessario seguire la risposta di @wim. Questa risposta presuppone che non puoi/non cambierò il comando stesso.

Il metodo di @Igor è il modo migliore quando disponibile, ma alcuni comandi ignorano l'argomento stdout.

@ Phob1a ha una soluzione che è fondamentalmente ok, ma ha il problema di chiudere stdout (quindi l'output futuro non funziona). Con alcune modifiche:

from django.core.management import call_command 
import sys 

stdout_backup, sys.stdout = sys.stdout, open('output_file', 'w+') 
call_command('your_command') 
sys.stdout = stdout_backup 

Si noti che se si vuole buttare via d'uscita solo, è necessario sostituire il primo comando:

from os import devnull 
stdout_backup, sys.stdout = sys.stdout, open(devnull, 'a') 
...