Completed
Pull Request — master (#191)
by
unknown
23s
created

render_field_variations()   B

Complexity

Conditions 5

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 3
Bugs 0 Features 0
Metric Value
c 3
b 0
f 0
dl 0
loc 15
rs 8.5454
cc 5
1
import logging
2
from concurrent.futures import ProcessPoolExecutor
3
from multiprocessing import cpu_count
4
5
import progressbar
6
from django.apps import apps
7
from django.core.files.storage import get_storage_class
8
from django.core.management import BaseCommand, CommandError
9
10
from stdimage.utils import render_variations
11
12
logger = logging.getLogger()
13
14
15
class Command(BaseCommand):
16
    help = 'Renders all variations of a StdImageField.'
17
    args = '<app.model.field app.model.field>'
18
19
    def add_arguments(self, parser):
20
        parser.add_argument('field_path',
21
                            nargs='+',
22
                            type=str,
23
                            help='<app.model.field app.model.field>')
24
        parser.add_argument('--replace',
25
                            action='store_true',
26
                            dest='replace',
27
                            default=False,
28
                            help='Replace existing files.')
29
30
        parser.add_argument('--ignore-missing',
31
                            action='store_true',
32
                            dest='ignore_missing',
33
                            default=False,
34
                            help='Do not rise exception on missing file '
35
                                 'and use log.error instead.')
36
37
    def handle(self, *args, **options):
38
        replace = options.get('replace', False)
39
        ignore_missing = options.get('ignore_missing', False)
40
        routes = options.get('field_path', [])
41
        for route in routes:
42
            try:
43
                app_label, model_name, field_name = route.rsplit('.')
44
            except ValueError:
45
                raise CommandError("Error parsing field_path '{}'. Use format "
46
                                   "<app.model.field app.model.field>."
47
                                   .format(route))
48
            model_class = apps.get_model(app_label, model_name)
49
            field = model_class._meta.get_field(field_name)
50
51
            queryset = model_class._default_manager \
52
                .exclude(**{'%s__isnull' % field_name: True}) \
53
                .exclude(**{field_name: ''})
54
            obj = queryset.first()
55
            do_render = True
56
            if obj:
57
                f = getattr(obj, field_name)
58
                do_render = f.field.render_variations
59
            images = queryset.values_list(field_name, flat=True).iterator()
60
            count = queryset.count()
61
62
            self.render(field, images, count, replace, ignore_missing,
63
                        do_render)
64
65
    @staticmethod
66
    def render(field, images, count, replace, ignore_missing, do_render):
67
        kwargs_list = (
68
            dict(
69
                file_name=file_name,
70
                do_render=do_render,
71
                variations=field.variations,
72
                replace=replace,
73
                storage=field.storage.deconstruct()[0],
74
                field_class=field.attr_class,
75
                ignore_missing=ignore_missing,
76
            )
77
            for file_name in images
78
        )
79
        with progressbar.ProgressBar(maxval=count, widgets=(
80
            progressbar.RotatingMarker(),
81
            ' | CPUs: {}'.format(cpu_count()),
82
            ' | ', progressbar.AdaptiveETA(),
83
            ' | ', progressbar.Percentage(),
84
            ' ', progressbar.Bar(),
85
        )) as bar:
86
            with ProcessPoolExecutor() as executor:
87
                for _ in executor.map(render_field_variations, kwargs_list):
88
                    bar += 1
89
90
91
def render_field_variations(kwargs):
92
    kwargs['storage'] = get_storage_class(kwargs['storage'])()
93
    ignore_missing = kwargs.pop('ignore_missing')
94
    do_render = kwargs.pop('do_render')
95
    try:
96
        if callable(do_render):
97
            kwargs.pop('field_class')
98
            do_render = do_render(**kwargs)
99
        if do_render:
100
            render_variations(**kwargs)
101
    except FileNotFoundError as e:
102
        if not ignore_missing:
103
            raise
104
        else:
105
            logger.error(str(e))
106