28

I am calling commands in Django from within a script similar to:

#!/usr/bin/python
from django.core.management import call_command
call_command('syncdb')
call_command('runserver')
call_command('inspectdb')

How to I assign the output from for instance call_command('inspectdb') to a variable or a file?

I've tried

var = call_command('inspectdb')

but 'var' remains none: purpose: inspect existing tables in legacy databases not created by django

Fenrir
  • 353
  • 4
  • 8
  • possible duplicate of [How to make db dumpfile in django](http://stackoverflow.com/questions/11546151/how-to-make-db-dumpfile-in-django) and [how to use call command with dumpdata command to save json to file](http://stackoverflow.com/questions/16075789/how-to-use-call-command-with-dumpdata-command-to-save-json-to-file) – fredtantini Oct 24 '14 at 21:57

2 Answers2

30

You have to redirect call_command's output, otherwise it just prints to stdout but returns nothing. You could try saving it to a file, then reading it in like this:

with open('/tmp/inspectdb', 'w+') as f:
    call_command('inspectdb', stdout=f)
    var = f.readlines()

EDIT: Looking at this a couple years later, a better solution would be to create a StringIO to redirect the output, instead of a real file. Here's an example from one of Django's test suites:

from io import StringIO

def test_command(self):
    out = StringIO()
    management.call_command('dance', stdout=out)
    self.assertIn("I don't feel like dancing Rock'n'Roll.\n", out.getvalue())
Rick Westera
  • 3,142
  • 1
  • 35
  • 23
BingsF
  • 1,269
  • 10
  • 15
  • 1
    tried this, but it does not seem to work, var becomes an empty list while running inspectdb on the commandline yields the inferred models. I'll try subprocess. – Fenrir Oct 25 '14 at 21:23
  • FWIW you were probably not using self.stdout.write() to do the output in the command. – Javi Romero Mar 25 '16 at 22:04
  • 1
    I don't see how `stdout=f` ever makes it to the Command constructor which is where `stdout` would be used. `call_command` calls `load_command_class(app_name, name)` and does not pass stdout and the Command is instantiated with no arguments like so `module.Command()`. And here is Command's constructor: `def __init__(self, stdout=None, stderr=None, no_color=False):` – Matt Oct 14 '16 at 03:57
  • 1
    @Matt: the stdout parameter gets captured in `**options`, transformed into a dictionary called `defaults`, and passed to the command as `command.execute(*args, **defaults)`. So you're right that it's not passed to the constructor; look at `Command.execute` instead. – BingsF Oct 17 '16 at 22:49
  • link to Django docs on `stdout` arg: https://docs.djangoproject.com/en/stable/ref/django-admin/#output-redirection – odigity Nov 22 '22 at 19:34
5

This is documented in the Django Documentation under "Running management commands from your code > Output redirection".

To save to a variable, you could do:

import io
from django.core.management import call_command


with io.StringIO() as out:
   call_command('dumpdata', stdout=out)
   print(out.getvalue())

To save to a file, you could do:

from django.core.management import call_command


with open('/path/to/command_output', 'w') as f:
    call_command('dumpdata', stdout=f)
Michael B
  • 5,148
  • 1
  • 28
  • 32