> Den 9. maj 2016 kl. 14.23 skrev Phil Gyford <
gyf...@gmail.com>:
>
> I have a custom management command which calls a method in another class, which fetches lots of data from a third-party API. Fetching the data could take a few seconds or it could take over an hour, depending on the quantity.
>
> [...]
> Things I've tried so far:
>
> 1) Using print(), e.g.:
>
> print('Fetched %d of %d' % (n, total), end='\r')
>
> In a loop, this nicely shows a single line that constantly updates with progress. But print() is nasty and when I run my unit tests, this output is displayed among the testing output. I assume it'll also be a pain to have that output when running the commands scheduled with cron (or whatever).
I do this kind of progress reporting a lot. Usually, I get around the test/cron output pollution by adding a 'silent' argument to the management command which determines if the commend should print progress reports or not. See below.
> 2) Using Django logging. This is "better" than print(), and doesn't mess up test output, but as far as I can tell there's no way to display a single, constantly updated, line showing progress. It's only going to show one line after another:
>
> Fetched 1 of 3000
> Fetched 2 of 3000
> Fetched 3 of 3000
It's actually quite simple. You need to create a custom handler like so:
import logging
import time
from django.core.management.base import BaseCommand
class OverwriteHandler(logging.StreamHandler):
# The extra spaces wipe previous output in case your messages are wariable-width
terminator = ' '*80 + '\r'
log = logging.getLogger('')
h = OverwriteHandler()
log.addHandler(h)
class Command(BaseCommand):
def handle(self, silent=False, **options):
log.setLevel(logging.DEBUG if silent else logging.INFO)
log.info('1 of 2')
time.sleep(1)
log.info('2 of 2')
time.sleep(1)
If you want to mix normal and progress logging in your management command, you need to use two loggers with different handlers.
Erik