2014-11-13 2 views
9

Я пытался перенаправить стандартный вывод команды пользовательского Джанго, используя этот кусок кода:Перенаправление management.call_command() стандартный вывод в файл

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

Однако, когда я называю это из управления. py, стандартный вывод появляется на консоли, и файл/tmp/output создается, но пуст.

Вот Джанго documentation того, что я пытаюсь сделать

+0

Я предполагаю, что, возможно, потому, что 'open ('/ tmp/output', 'r +')' открывает файл только для _reading_, но вы должны иметь возможность писать ему – Anentropic

+0

@ Annropic 'r +' означает чтение и написать. Я уже пробовал с «w», и я получаю тот же результат – Phob1a

+0

oops, вы правы!:) – Anentropic

ответ

5

Этот вопрос уже год назад, но я 99% конечно, у меня есть правильный ответ, который остальные 3 пропустили. Поэтому я оставлю это здесь, чтобы помочь будущим читателям:

Ваша команда, вероятно, просто использует print. Для того, чтобы быть в состоянии захватить или перенаправлять печать в команде управления, вы хотите использовать self.stdout ручку экземпляра команды:

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

Если вы совсем не можете изменить заявление багги печати из команды (это код в 'basequery' команда при ошибке в вашем примере), то вы можете использовать диспетчер контекста для временно перенаправить stdout, чтобы захватить этот вывод. Важно, чтобы восстановить старую версию после перенаправления. См. contextlib.redirect_stdout.

+1

Или просто используйте self.stdout.write ('...') – tbm

0

Я использую это, чтобы перенаправить вывод в файл

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

Я пробовал свой метод, но получаю тот же результат. Командная строка продолжает печатать stdout и метод StringIO .read() после выполнения .seek (0) ничего не возвращает. Тот же результат, что и передача stdout = f. – Phob1a

+0

Можете ли вы предоставить фактический код, который вы используете с StringIO? – Igor

+0

уверен. Я разместил его как ответ ниже. – Phob1a

-2

Я попытался приближение Игоря, используя следующий код:

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

У меня такой же результат: пустой файл и stdout, появляющиеся в консоли. Может быть, это потому, что я вызываю команды django из команды django?

Во всяком случае, мне удалось решить проблему таким образом:

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

Я знаю, что это уродливое решение, но это единственный способ, которым я сделал его работу.

+1

Это прерывает stdout, если вы печатаете что-либо после этого кода, вы получаете 'ValueError: операцию ввода-вывода в закрытом файле.' – Mark

+0

не удалось ли это зафиксировать, сохранив 'sys.stdout' во временную переменную и восстановив ее после? – spectras

2

Если у вас есть контроль над кодом команды управления, вам следует следовать по адресу @wim. Этот ответ предполагает, что вы не можете/не будете изменять команду.

Метод by @Igor - лучший способ, когда он доступен, но некоторые команды игнорируют аргумент stdout.

@ У Phob1a есть решение, которое в принципе нормально, но имеет проблему закрытия stdout (поэтому будущий вывод на него не работает). С некоторыми изменениями:

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 

Обратите внимание, что если вы хотите просто выбросить вывод, вы должны заменить первую команду:

from os import devnull 
stdout_backup, sys.stdout = sys.stdout, open(devnull, 'a') 
... 
Смежные вопросы