Completed
Pull Request — master (#191)
by
unknown
24s
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('--igrnore-missing',
31
                            action='store_true',
32
                            dest='igrnore_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
        igrnore_missing = options.get('igrnore_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, igrnore_missing, do_render)
63
64
    @staticmethod
65
    def render(field, images, count, replace, igrnore_missing, do_render):
66
        kwargs_list = (
67
            dict(
68
                file_name=file_name,
69
                do_render=do_render,
70
                variations=field.variations,
71
                replace=replace,
72
                storage=field.storage.deconstruct()[0],
73
                field_class=field.attr_class,
74
                igrnore_missing=igrnore_missing,
75
            )
76
            for file_name in images
77
        )
78
        with progressbar.ProgressBar(maxval=count, widgets=(
79
            progressbar.RotatingMarker(),
80
            ' | CPUs: {}'.format(cpu_count()),
81
            ' | ', progressbar.AdaptiveETA(),
82
            ' | ', progressbar.Percentage(),
83
            ' ', progressbar.Bar(),
84
        )) as bar:
85
            with ProcessPoolExecutor() as executor:
86
                for _ in executor.map(render_field_variations, kwargs_list):
87
                    bar += 1
88
89
90
def render_field_variations(kwargs):
91
    kwargs['storage'] = get_storage_class(kwargs['storage'])()
92
    igrnore_missing = kwargs.pop('igrnore_missing')
93
    do_render = kwargs.pop('do_render')
94
    try:
95
        if callable(do_render):
96
            kwargs.pop('field_class')
97
            do_render = do_render(**kwargs)
98
        if do_render:
99
            render_variations(**kwargs)
100
    except FileNotFoundError as e:
101
        if not igrnore_missing:
102
            raise
103
        else:
104
            logger.error(str(e))
105