Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redirect management.call_command() stdout to a file

Tags:

python

django

I've been trying to redirect the standard output of a custom django command using this piece of code:

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

However, when I call this from manage.py the standard output appears on the console and the /tmp/output file is created but empty.

Here's the django documentation of what I'm trying to do

like image 586
Phob1a Avatar asked Nov 13 '14 13:11

Phob1a


2 Answers

Your command is probably just using print directly. To be able to capture or redirect prints in a management command, you'll want to use the self.stdout handle of the command instance:

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

If you're unable change the print calls within the command (which is the code within 'basequery' in your example), then you can use a context manager to temporarily redirect stdout in order to capture that output. It's important to restore the old stdout after redirection. See contextlib.redirect_stdout.

like image 141
wim Avatar answered Oct 08 '22 13:10

wim


If you have control over the code of the management command, then you should follow the answer by @wim. This answer assumes you can't/won't change the command itself.

The method by @Igor is the best way when available, but some commands ignore stdout argument.

@Phob1a has a solution that is basically okay but has the problem of closing stdout (so future output to it doesn't work). With some changes:

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

Note that if you want to just throw away output, you should replace the first command:

from os import devnull
stdout_backup, sys.stdout = sys.stdout, open(devnull, 'a')
...
like image 22
Mark Avatar answered Oct 08 '22 14:10

Mark