Python 重定向管理。将_命令()标准输出调用到文件
我一直在尝试使用以下代码重定向自定义django命令的标准输出:Python 重定向管理。将_命令()标准输出调用到文件,python,django,Python,Django,我一直在尝试使用以下代码重定向自定义django命令的标准输出: 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.ca
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()
但是,当我从manage.py调用它时,控制台上会显示标准输出,/tmp/output文件已创建但为空
这是我要做的工作的要点我用它将输出重定向到文件
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()
我使用它将输出重定向到文件
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的近似:
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()
我得到了同样的结果:控制台中出现了空文件和标准输出。可能是因为我在用django命令调用django命令
无论如何,我设法用这种方法解决了这个问题:
sys.stdout = open('/tmp/output', 'w+')
management.call_command('basequery', 'list', 'log')
sys.stdout.close()
我知道这是一个丑陋的解决方案,但这是我唯一能让它工作的方法。我使用以下代码尝试了Igor的近似:
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()
我得到了同样的结果:控制台中出现了空文件和标准输出。可能是因为我在用django命令调用django命令
无论如何,我设法用这种方法解决了这个问题:
sys.stdout = open('/tmp/output', 'w+')
management.call_command('basequery', 'list', 'log')
sys.stdout.close()
我知道这是一个丑陋的解决方案,但这是我让它工作的唯一方法。如果您可以控制管理命令的代码,那么您应该按照@wim的答案来操作。这个答案假设您不能/不会更改命令本身 如果可用,@Igor的方法是最好的方法,但是有些命令忽略
stdout
参数
@Phob1a有一个基本上可以解决的解决方案,但存在关闭标准输出的问题(因此将来的输出无法工作)。有一些变化:
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')
...
如果您可以控制管理命令的代码,那么您应该按照@wim的答案进行操作。这个答案假设您不能/不会更改命令本身 如果可用,@Igor的方法是最好的方法,但是有些命令忽略
stdout
参数
@Phob1a有一个基本上可以解决的解决方案,但存在关闭标准输出的问题(因此将来的输出无法工作)。有一些变化:
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')
...
您的命令可能只是直接使用
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以捕获该输出。重定向后恢复旧标准输出非常重要。请参阅。您的命令可能只是直接使用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以捕获该输出。重定向后恢复旧标准输出非常重要。请参阅。我猜可能是因为open('/tmp/output','r+')
打开文件只是为了读取,但您需要能够写入it@Anentropic“r+”表示读写。我已经用“w”试过了,我得到了同样的结果,你是对的!:)如果您只使用这个新的管理命令调用另一个将其输出写入文件的命令,您可以将结果通过管道传输到命令行上的一个文件。@schillingt我使用这个新的管理命令触发多个django命令并捕获它们的stdout和stderr来计算指标。我猜可能是因为open(“/tmp/output”、“r+”)
打开该文件仅用于读取,但您需要能够写入it@Anentropic“r+”表示读和写。我已经用“w”尝试过了,我得到了相同的结果toops,你是对的!:)如果你只使用这个新的管理命令调用另一个将其输出写入文件的命令,您可以将结果通过管道传输到命令行上的一个文件。@schillingt我正在使用这个新的管理命令触发多个django命令,并捕获它们的stdout和stderr来计算度量。我尝试了您的方法,但得到了相同的结果。执行此操作后,命令行继续打印stdout和StringIO.read()方法。seek(0)不返回任何内容。与传递stdout=f的结果相同。您能提供与StringIO一起使用的实际代码吗?当然。我把它作为一个答案贴在下面。如果命令定义了自己的stdout参数,这就不起作用了。我尝试了你的方法,但得到了相同的结果。执行此操作后,命令行继续打印stdout和StringIO.read()方法。seek(0)不返回任何内容。与传递stdout=f的结果相同。您能提供与StringIO一起使用的实际代码吗?当然。我在下面将其作为答案发布。如果命令定义了自己的stdout参数,这将不起作用。这将中断stdout,如果在此代码之后打印任何内容,您将获得value错误:对关闭的文件执行I/O操作。
是否可以通过将sys.stdout
保存到临时变量并在之后恢复它来修复?这将中断stdout,如果在此代码之后打印任何内容,您将得到ValueError:I/O操作关闭的文件。
是否可以通过将sys.stdout
保存到临时变量并在之后恢复它来修复它?