[Fixed]-Redirect management.call_command() stdout to a file

17👍

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.

👤wim

8👍

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')
...
👤Mark

0👍

I am using this to redirect output to 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()
👤Igor

-2👍

I tried Igor’s approximation using the following code:

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

I got the same result tough: empty file and stdout appearing in the console. Maybe that’s because I’m calling django commands from a django command?

Anyway, I managed to solve the problem this way:

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

I know it is an ugly solution but it’s the only way I made it work.

👤Phob1a

Leave a comment