首页 > 解决方案 > Django 管理命令不刷新标准输出

问题描述

我正在尝试在 Django 管理命令中处理需要一段时间的处理前后打印到控制台,如下所示:

import requests
import xmltodict

from django.core.management.base import BaseCommand


def get_all_routes():
    url = 'http://busopen.jeju.go.kr/OpenAPI/service/bis/Bus'

    r = requests.get(url)
    data = xmltodict.parse(r.content)

    return data['response']['body']['items']['item']


class Command(BaseCommand):

    help = 'Updates the database via Bus Info API'

    def handle(self, *args, **options):
        self.stdout.write('Saving routes ... ', ending='')
        for route in get_all_routes():
            route_obj = Route(
                route_type=route['routeTp'], route_id=route['routeId'], route_number=route['routeNum'])
            route_obj.save()
        self.stdout.write('done.')

在上面的代码中,Saving routes ...预计在循环开始之前done.打印,并在循环完成时打印在它旁边,这样它看起来就像Saving routes ... done.在结束时一样。

但是,前者在循环完成之前不会打印,当两个字符串最终同时打印时,这不是我所期望的。

我发现了这个问题,答案建议刷新输出 ie self.stdout.flush(),所以我将它添加到我的代码中:

    def handle(self, *args, **options):
        self.stdout.write('Saving routes ... ', ending='')
        self.stdout.flush()
        for route in get_all_routes():
            route_obj = Route(
                route_type=route['routeTp'], route_id=route['routeId'], route_number=route['routeNum'])
            route_obj.save()
        self.stdout.write('done.')

尽管如此,结果仍然没有改变。

我做错了什么?

标签: pythondjangoprinting

解决方案


要记住的是您正在使用 self.stdout(如 Django 文档中所建议的那样),它是 BaseCommand 对 Python 标准 sys.stdout 的覆盖。与您的问题相关的两者之间有两个主要区别:

  1. BaseCommand 的 self.stdout.write() 版本中的默认“结尾”是换行符,迫使您使用结尾=''参数,这与默认为空结尾的 sys.stdout.write() 不同。这本身不会导致您的问题。
  2. Flush() 的 BaseCommand 版本实际上并没有做任何事情(谁会想到?)。这是一个已知的错误:https ://code.djangoproject.com/ticket/29533

所以你真的有两个选择:

  1. 不使用 BaseCommand 的 self.stdout,而是使用 sys.stdout,在这种情况下,刷新确实有效
  2. 通过将“-u”参数传递给 python,在运行管理命令时强制标准输出完全无缓冲。所以不是运行python manage.py <subcommand>,而是运行python -u manage.py <subcommand>

希望这可以帮助。


推荐阅读