educommon 3.12.0__py3-none-any.whl → 3.13.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- educommon/__init__.py +0 -1
- educommon/about/ui/actions.py +16 -30
- educommon/about/ui/ui.py +3 -12
- educommon/about/utils.py +6 -5
- educommon/async_task/__init__.py +0 -1
- educommon/async_task/actions.py +18 -13
- educommon/async_task/apps.py +4 -0
- educommon/async_task/locker.py +2 -5
- educommon/async_task/migrations/0001_initial.py +55 -9
- educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
- educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
- educommon/async_task/models.py +9 -6
- educommon/async_task/tasks.py +11 -7
- educommon/async_task/ui.py +16 -35
- educommon/async_tasks/__init__.py +0 -1
- educommon/async_tasks/apps.py +4 -0
- educommon/async_tasks/locks.py +11 -21
- educommon/async_tasks/migrations/0001_initial.py +68 -8
- educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
- educommon/async_tasks/models.py +9 -29
- educommon/async_tasks/tasks.py +25 -54
- educommon/audit_log/__init__.py +1 -0
- educommon/audit_log/actions.py +27 -36
- educommon/audit_log/app_meta.py +7 -4
- educommon/audit_log/apps.py +44 -29
- educommon/audit_log/constants.py +7 -4
- educommon/audit_log/error_log/actions.py +1 -3
- educommon/audit_log/helpers.py +2 -4
- educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
- educommon/audit_log/migrations/0001_initial.py +91 -16
- educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
- educommon/audit_log/migrations/0003_logproxy.py +1 -3
- educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
- educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
- educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
- educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
- educommon/audit_log/migrations/0008_table_logged.py +0 -1
- educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
- educommon/audit_log/models.py +36 -42
- educommon/audit_log/permissions.py +11 -9
- educommon/audit_log/proxies.py +12 -23
- educommon/audit_log/ui.py +18 -15
- educommon/audit_log/utils/__init__.py +28 -60
- educommon/audit_log/utils/operations.py +16 -2
- educommon/auth/__init__.py +0 -3
- educommon/auth/rbac/__init__.py +2 -4
- educommon/auth/rbac/actions.py +148 -145
- educommon/auth/rbac/app_meta.py +9 -6
- educommon/auth/rbac/backends/base.py +2 -8
- educommon/auth/rbac/backends/caching.py +27 -37
- educommon/auth/rbac/backends/simple.py +1 -4
- educommon/auth/rbac/checker.py +1 -3
- educommon/auth/rbac/management/commands/rbac.py +6 -11
- educommon/auth/rbac/manager.py +18 -47
- educommon/auth/rbac/migrations/0001_initial.py +73 -12
- educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
- educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
- educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
- educommon/auth/rbac/models.py +63 -68
- educommon/auth/rbac/permissions.py +6 -7
- educommon/auth/rbac/ui.py +83 -84
- educommon/auth/rbac/utils.py +10 -11
- educommon/auth/rbac/validators.py +4 -5
- educommon/auth/simple_auth/__init__.py +1 -5
- educommon/auth/simple_auth/actions.py +79 -92
- educommon/auth/simple_auth/app_meta.py +2 -9
- educommon/auth/simple_auth/checkers.py +3 -3
- educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
- educommon/auth/simple_auth/validators.py +0 -1
- educommon/contingent/actions.py +7 -7
- educommon/contingent/app_meta.py +1 -4
- educommon/contingent/base.py +10 -15
- educommon/contingent/catalogs.py +424 -540
- educommon/contingent/contingent_plugin/actions.py +4 -15
- educommon/contingent/contingent_plugin/apps.py +10 -4
- educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
- educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
- educommon/contingent/contingent_plugin/model_views.py +2 -12
- educommon/contingent/contingent_plugin/models.py +2 -7
- educommon/contingent/contingent_plugin/observer.py +14 -13
- educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
- educommon/contingent/contingent_plugin/storage.py +8 -7
- educommon/contingent/contingent_plugin/utils.py +6 -6
- educommon/django/db/fields.py +72 -86
- educommon/django/db/migration/__init__.py +3 -7
- educommon/django/db/migration/operations.py +29 -51
- educommon/django/db/mixins/__init__.py +16 -10
- educommon/django/db/mixins/date_interval.py +47 -75
- educommon/django/db/mixins/validation.py +26 -26
- educommon/django/db/model_view/__init__.py +18 -22
- educommon/django/db/models.py +9 -8
- educommon/django/db/observer.py +9 -27
- educommon/django/db/partitioning/__init__.py +66 -92
- educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
- educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
- educommon/django/db/partitioning/management/commands/split_table.py +18 -13
- educommon/django/db/routers.py +6 -15
- educommon/django/db/signals.py +149 -2
- educommon/django/db/utils.py +14 -19
- educommon/django/db/validators/__init__.py +1 -0
- educommon/django/db/validators/simple.py +72 -100
- educommon/django/storages/atcfs/api.py +39 -53
- educommon/django/storages/atcfs/app_meta.py +1 -1
- educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
- educommon/django/storages/atcfs/models.py +0 -3
- educommon/django/storages/atcfs/monkey_patching.py +18 -12
- educommon/django/storages/atcfs/storage.py +14 -23
- educommon/extjs/fields/input_params.py +15 -45
- educommon/importer/XLSReader.py +143 -241
- educommon/importer/__init__.py +86 -4
- educommon/importer/api.py +53 -84
- educommon/importer/constants.py +4 -14
- educommon/importer/loggers.py +16 -26
- educommon/importer/proxy.py +131 -176
- educommon/importer/proxy_import.py +11 -12
- educommon/importer/report.py +4 -6
- educommon/importer/ui.py +32 -26
- educommon/importer/validators.py +4 -7
- educommon/integration_entities/helpers.py +14 -18
- educommon/ioc/__init__.py +3 -6
- educommon/logger/loggers.py +10 -14
- educommon/m3/__init__.py +20 -38
- educommon/m3/extensions/__init__.py +1 -0
- educommon/m3/extensions/listeners/__init__.py +22 -38
- educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
- educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
- educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
- educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
- educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
- educommon/m3/extensions/ui.py +15 -33
- educommon/m3/transaction_context.py +17 -19
- educommon/objectpack/actions.py +70 -88
- educommon/objectpack/apps.py +5 -0
- educommon/objectpack/filters.py +9 -15
- educommon/objectpack/ui.py +59 -77
- educommon/report/__init__.py +9 -5
- educommon/report/actions.py +29 -32
- educommon/report/constructor/__init__.py +5 -8
- educommon/report/constructor/app_meta.py +1 -3
- educommon/report/constructor/apps.py +1 -0
- educommon/report/constructor/base.py +33 -80
- educommon/report/constructor/builders/excel/_base.py +138 -286
- educommon/report/constructor/builders/excel/_header.py +2 -9
- educommon/report/constructor/builders/excel/product.py +13 -34
- educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
- educommon/report/constructor/config.py +2 -0
- educommon/report/constructor/editor/actions.py +101 -215
- educommon/report/constructor/editor/ui.py +71 -93
- educommon/report/constructor/exceptions.py +6 -12
- educommon/report/constructor/migrations/0001_initial.py +36 -44
- educommon/report/constructor/migrations/0002_report_filters.py +86 -72
- educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
- educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
- educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
- educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
- educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
- educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
- educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
- educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
- educommon/report/constructor/mixins.py +14 -15
- educommon/report/constructor/models.py +76 -124
- educommon/report/constructor/utils.py +3 -8
- educommon/report/constructor/validators.py +1 -3
- educommon/report/reporter.py +25 -43
- educommon/report/utils.py +14 -40
- educommon/rest/actions.py +7 -11
- educommon/rest/context.py +6 -16
- educommon/rest/controllers.py +10 -10
- educommon/rest/mixins.py +29 -27
- educommon/secure_media/app_meta.py +9 -9
- educommon/utils/__init__.py +3 -2
- educommon/utils/caching.py +1 -3
- educommon/utils/conversion.py +1 -3
- educommon/utils/crypto.py +1 -2
- educommon/utils/date.py +13 -26
- educommon/utils/db/__init__.py +17 -26
- educommon/utils/db/postgresql.py +1 -4
- educommon/utils/fonts/__init__.py +3 -4
- educommon/utils/licence/__init__.py +5 -16
- educommon/utils/misc.py +9 -18
- educommon/utils/object_grid.py +55 -62
- educommon/utils/phone_number/modelfields.py +1 -3
- educommon/utils/phone_number/phone_number.py +5 -8
- educommon/utils/phone_number/validators.py +8 -23
- educommon/utils/plugins.py +15 -28
- educommon/utils/registry.py +2 -1
- educommon/utils/seqtools.py +1 -3
- educommon/utils/serializer.py +9 -16
- educommon/utils/storage.py +3 -2
- educommon/utils/system.py +1 -3
- educommon/utils/system_app/management/commands/delete_objects.py +17 -34
- educommon/utils/ui.py +87 -84
- educommon/utils/xml/__init__.py +2 -7
- educommon/utils/xml/resolver.py +1 -0
- educommon/ws_log/actions.py +31 -76
- educommon/ws_log/base.py +6 -20
- educommon/ws_log/migrations/0001_initial.py +25 -8
- educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
- educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
- educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
- educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
- educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
- educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
- educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
- educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
- educommon/ws_log/models.py +21 -35
- educommon/ws_log/provider.py +2 -1
- educommon/ws_log/report.py +8 -13
- educommon/ws_log/smev/applications.py +12 -27
- educommon/ws_log/smev/exceptions.py +2 -3
- educommon/ws_log/ui.py +32 -32
- educommon/ws_log/utils.py +1 -3
- educommon-3.13.2.dist-info/METADATA +57 -0
- educommon-3.13.2.dist-info/RECORD +354 -0
- {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +1 -1
- educommon/utils/patches.py +0 -27
- educommon/version.conf +0 -11
- educommon-3.12.0.dist-info/METADATA +0 -47
- educommon-3.12.0.dist-info/RECORD +0 -357
- educommon-3.12.0.dist-info/dependency_links.txt +0 -1
- {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
@@ -128,28 +128,17 @@ class FilterValuesProvider:
|
|
128
128
|
"""
|
129
129
|
|
130
130
|
if column_descriptor.data_type == constants.CT_CHOICES:
|
131
|
-
return get_field_value_by_display(
|
132
|
-
column_descriptor.field,
|
133
|
-
value
|
134
|
-
) if self._as_orm_filter else value
|
131
|
+
return get_field_value_by_display(column_descriptor.field, value) if self._as_orm_filter else value
|
135
132
|
else:
|
136
133
|
if isinstance(column_descriptor.field.formfield(), BooleanField):
|
137
|
-
if (
|
138
|
-
isinstance(value, str) and
|
139
|
-
value.lower() in ('false', '0', 'нет')
|
140
|
-
):
|
134
|
+
if isinstance(value, str) and value.lower() in ('false', '0', 'нет'):
|
141
135
|
return False if self._as_orm_filter else FALSE
|
142
136
|
|
143
|
-
elif (
|
144
|
-
isinstance(value, str) and
|
145
|
-
value.lower() in ('true', '1', 'да')
|
146
|
-
):
|
137
|
+
elif isinstance(value, str) and value.lower() in ('true', '1', 'да'):
|
147
138
|
return True if self._as_orm_filter else TRUE
|
148
139
|
|
149
140
|
else:
|
150
|
-
raise FilterError(
|
151
|
-
report_filter, 'неправильно задано значение фильтра'
|
152
|
-
)
|
141
|
+
raise FilterError(report_filter, 'неправильно задано значение фильтра')
|
153
142
|
|
154
143
|
return column_descriptor.field.formfield().to_python(value)
|
155
144
|
|
@@ -168,33 +157,19 @@ class FilterValuesProvider:
|
|
168
157
|
result = None
|
169
158
|
|
170
159
|
elif report_filter.operator == constants.IN:
|
171
|
-
result = tuple(
|
172
|
-
self.to_python(value, report_filter, column_descriptor)
|
173
|
-
for value in report_filter.values
|
174
|
-
)
|
160
|
+
result = tuple(self.to_python(value, report_filter, column_descriptor) for value in report_filter.values)
|
175
161
|
|
176
162
|
elif report_filter.operator == constants.BETWEEN:
|
177
|
-
result = tuple(
|
178
|
-
self.to_python(value, report_filter, column_descriptor)
|
179
|
-
for value in report_filter.values
|
180
|
-
)
|
163
|
+
result = tuple(self.to_python(value, report_filter, column_descriptor) for value in report_filter.values)
|
181
164
|
|
182
165
|
if len(result) != 2:
|
183
|
-
raise FilterError(
|
184
|
-
report_filter, 'не правильно заданы границы диапазона'
|
185
|
-
)
|
166
|
+
raise FilterError(report_filter, 'не правильно заданы границы диапазона')
|
186
167
|
|
187
168
|
elif report_filter.values:
|
188
|
-
result = self.to_python(
|
189
|
-
report_filter.values[0],
|
190
|
-
report_filter,
|
191
|
-
column_descriptor
|
192
|
-
)
|
169
|
+
result = self.to_python(report_filter.values[0], report_filter, column_descriptor)
|
193
170
|
|
194
171
|
else:
|
195
|
-
raise FilterError(
|
196
|
-
report_filter, 'не указано значение для сравнения.'
|
197
|
-
)
|
172
|
+
raise FilterError(report_filter, 'не указано значение для сравнения.')
|
198
173
|
|
199
174
|
return result
|
200
175
|
|
@@ -204,10 +179,7 @@ def is_row(data):
|
|
204
179
|
|
205
180
|
:rtype: bool
|
206
181
|
"""
|
207
|
-
return (
|
208
|
-
isinstance(data, (tuple, list)) and
|
209
|
-
any(not isinstance(cell, (tuple, list)) for cell in data)
|
210
|
-
)
|
182
|
+
return isinstance(data, (tuple, list)) and any(not isinstance(cell, (tuple, list)) for cell in data)
|
211
183
|
|
212
184
|
|
213
185
|
def is_block(data):
|
@@ -215,11 +187,7 @@ def is_block(data):
|
|
215
187
|
|
216
188
|
:rtype: bool
|
217
189
|
"""
|
218
|
-
return (
|
219
|
-
data and
|
220
|
-
isinstance(data, (tuple, list)) and
|
221
|
-
all(isinstance(row, (tuple, list)) for row in data)
|
222
|
-
)
|
190
|
+
return data and isinstance(data, (tuple, list)) and all(isinstance(row, (tuple, list)) for row in data)
|
223
191
|
|
224
192
|
|
225
193
|
def get_data_width(data):
|
@@ -255,9 +223,7 @@ class _FilterBuilder:
|
|
255
223
|
educommon.report.constructor.base.ColumnDescriptor
|
256
224
|
"""
|
257
225
|
assert isinstance(report_filter, ReportFilter), type(report_filter)
|
258
|
-
assert isinstance(column_descriptor, ColumnDescriptor), type(
|
259
|
-
column_descriptor
|
260
|
-
)
|
226
|
+
assert isinstance(column_descriptor, ColumnDescriptor), type(column_descriptor)
|
261
227
|
|
262
228
|
self._report_filter = report_filter
|
263
229
|
self._column_descriptor = column_descriptor
|
@@ -271,10 +237,7 @@ class _FilterBuilder:
|
|
271
237
|
|
272
238
|
:param str field_lookup: lookup-выражение для доступа к значению поля
|
273
239
|
"""
|
274
|
-
if
|
275
|
-
not self._report_filter.case_sensitive and
|
276
|
-
self._column_descriptor.data_type == constants.CT_TEXT
|
277
|
-
):
|
240
|
+
if not self._report_filter.case_sensitive and self._column_descriptor.data_type == constants.CT_TEXT:
|
278
241
|
field_lookup += {
|
279
242
|
constants.EQ: '__iexact',
|
280
243
|
constants.CONTAINS: '__icontains',
|
@@ -303,16 +266,14 @@ class _FilterBuilder:
|
|
303
266
|
values = True
|
304
267
|
|
305
268
|
elif (
|
306
|
-
not self._report_filter.case_sensitive
|
307
|
-
self._column_descriptor.data_type == constants.CT_TEXT
|
308
|
-
self._report_filter.operator == constants.IN
|
269
|
+
not self._report_filter.case_sensitive
|
270
|
+
and self._column_descriptor.data_type == constants.CT_TEXT
|
271
|
+
and self._report_filter.operator == constants.IN
|
309
272
|
):
|
310
273
|
values = tuple(v.lower() for v in self._report_filter.values)
|
311
274
|
|
312
275
|
else:
|
313
|
-
values = FilterValuesProvider()(
|
314
|
-
self._report_filter, self._column_descriptor
|
315
|
-
)
|
276
|
+
values = FilterValuesProvider()(self._report_filter, self._column_descriptor)
|
316
277
|
|
317
278
|
return values
|
318
279
|
|
@@ -327,18 +288,17 @@ class _FilterBuilder:
|
|
327
288
|
|
328
289
|
if self._report_filter.operator == constants.IS_NULL:
|
329
290
|
if self._column_descriptor.data_type == constants.CT_TEXT:
|
330
|
-
result = Q(
|
331
|
-
Q(**{field_lookup + '__isnull': True}) |
|
332
|
-
Q(**{field_lookup: ''})
|
333
|
-
)
|
291
|
+
result = Q(Q(**{f'{field_lookup}__isnull': True}) | Q(**{field_lookup: ''}))
|
334
292
|
else:
|
335
|
-
result = Q(**{field_lookup
|
293
|
+
result = Q(**{f'{field_lookup}__isnull': True})
|
336
294
|
|
337
295
|
else:
|
338
296
|
try:
|
339
|
-
result = Q(
|
340
|
-
|
341
|
-
|
297
|
+
result = Q(
|
298
|
+
**{
|
299
|
+
self._get_lookup(field_lookup): filter_values,
|
300
|
+
}
|
301
|
+
)
|
342
302
|
except ValueError as error:
|
343
303
|
raise FilterError(self._report_filter, str(error))
|
344
304
|
|
@@ -362,9 +322,7 @@ class _FilterGroupBuilder:
|
|
362
322
|
educommon.report.constructor.models.ReportFilterGroup
|
363
323
|
"""
|
364
324
|
assert isinstance(data_filterer, _DataFilterer), type(data_filterer)
|
365
|
-
assert isinstance(filter_group, ReportFilterGroup), type(
|
366
|
-
filter_group
|
367
|
-
)
|
325
|
+
assert isinstance(filter_group, ReportFilterGroup), type(filter_group)
|
368
326
|
|
369
327
|
self._data_filterer = data_filterer
|
370
328
|
self._filter_group = filter_group
|
@@ -382,13 +340,9 @@ class _FilterGroupBuilder:
|
|
382
340
|
|
383
341
|
for report_filter in self._data_filterer.filters_by_id.values():
|
384
342
|
if report_filter.group_id == self._filter_group.id:
|
385
|
-
column_descriptor = data_source.get_column_descriptor(
|
386
|
-
report_filter.column.name
|
387
|
-
)
|
343
|
+
column_descriptor = data_source.get_column_descriptor(report_filter.column.name)
|
388
344
|
if isinstance(column_descriptor.field, models.Field):
|
389
|
-
filter_builder = _FilterBuilder(
|
390
|
-
report_filter, column_descriptor
|
391
|
-
)
|
345
|
+
filter_builder = _FilterBuilder(report_filter, column_descriptor)
|
392
346
|
yield filter_builder.get_orm_filter()
|
393
347
|
|
394
348
|
def get_orm_filter(self):
|
@@ -402,18 +356,12 @@ class _FilterGroupBuilder:
|
|
402
356
|
}
|
403
357
|
|
404
358
|
if self._filter_group.operator not in operators:
|
405
|
-
raise ApplicationLogicException(
|
406
|
-
'Неподдерживаемый оператор: {}'
|
407
|
-
.format(self._filter_group.operator)
|
408
|
-
)
|
359
|
+
raise ApplicationLogicException('Неподдерживаемый оператор: {}'.format(self._filter_group.operator))
|
409
360
|
|
410
361
|
orm_filters = tuple(self._get_nested_orm_filters())
|
411
362
|
|
412
363
|
if orm_filters:
|
413
|
-
result = reduce(
|
414
|
-
operators[self._filter_group.operator],
|
415
|
-
orm_filters
|
416
|
-
)
|
364
|
+
result = reduce(operators[self._filter_group.operator], orm_filters)
|
417
365
|
else:
|
418
366
|
result = Q()
|
419
367
|
|
@@ -429,8 +377,7 @@ class _DataFilterer:
|
|
429
377
|
2. Фильтрация полученных данных в приложении.
|
430
378
|
"""
|
431
379
|
|
432
|
-
def __init__(self, report_template, data_source_descriptor,
|
433
|
-
report_columns, ignored_columns_ids):
|
380
|
+
def __init__(self, report_template, data_source_descriptor, report_columns, ignored_columns_ids):
|
434
381
|
"""Инициализация экземпляра класса.
|
435
382
|
|
436
383
|
:param report_template: Шаблон фильтра.
|
@@ -447,9 +394,7 @@ class _DataFilterer:
|
|
447
394
|
:param ignored_columns_ids: Колонки исключенные из отчета.
|
448
395
|
:type: tuple
|
449
396
|
"""
|
450
|
-
assert isinstance(report_template, ReportTemplate), type(
|
451
|
-
report_template
|
452
|
-
)
|
397
|
+
assert isinstance(report_template, ReportTemplate), type(report_template)
|
453
398
|
|
454
399
|
self._report_template = report_template
|
455
400
|
self.data_source_descriptor = data_source_descriptor
|
@@ -464,14 +409,9 @@ class _DataFilterer:
|
|
464
409
|
"""
|
465
410
|
query = ReportFilter.objects.filter(
|
466
411
|
group__report_template=self._report_template,
|
467
|
-
).exclude(
|
468
|
-
column_id__in=self._ignored_columns_ids
|
469
|
-
)
|
412
|
+
).exclude(column_id__in=self._ignored_columns_ids)
|
470
413
|
|
471
|
-
return {
|
472
|
-
report_filter.id: report_filter
|
473
|
-
for report_filter in query
|
474
|
-
}
|
414
|
+
return {report_filter.id: report_filter for report_filter in query}
|
475
415
|
|
476
416
|
def get_orm_filters(self):
|
477
417
|
"""Возвращает фильтры для формирования SQL-запроса.
|
@@ -486,9 +426,7 @@ class _DataFilterer:
|
|
486
426
|
|
487
427
|
:rtype: django.db.models.Q
|
488
428
|
"""
|
489
|
-
filter_group = self._report_template.filter_groups.filter(
|
490
|
-
parent__isnull=True
|
491
|
-
).first()
|
429
|
+
filter_group = self._report_template.filter_groups.filter(parent__isnull=True).first()
|
492
430
|
|
493
431
|
if filter_group:
|
494
432
|
return _FilterGroupBuilder(self, filter_group).get_orm_filter()
|
@@ -501,84 +439,82 @@ class _DataFilterer:
|
|
501
439
|
:rtype: callable
|
502
440
|
"""
|
503
441
|
data_source = self.data_source_descriptor
|
504
|
-
column_descriptor = data_source.get_column_descriptor(
|
505
|
-
|
506
|
-
)
|
507
|
-
filter_values = FilterValuesProvider(as_orm_filter=False)(
|
508
|
-
report_filter, column_descriptor
|
509
|
-
)
|
442
|
+
column_descriptor = data_source.get_column_descriptor(report_filter.column.name)
|
443
|
+
filter_values = FilterValuesProvider(as_orm_filter=False)(report_filter, column_descriptor)
|
510
444
|
|
511
445
|
if report_filter.operator == constants.LE:
|
446
|
+
|
512
447
|
def function(value):
|
513
448
|
return value is not None and value <= filter_values
|
514
449
|
|
515
450
|
elif report_filter.operator == constants.LT:
|
451
|
+
|
516
452
|
def function(value):
|
517
453
|
return value is not None and value < filter_values
|
518
454
|
|
519
455
|
elif report_filter.operator == constants.EQ:
|
456
|
+
|
520
457
|
def function(value):
|
521
458
|
return value == filter_values
|
522
459
|
|
523
460
|
elif report_filter.operator == constants.GT:
|
461
|
+
|
524
462
|
def function(value):
|
525
463
|
return value is not None and value > filter_values
|
526
464
|
|
527
465
|
elif report_filter.operator == constants.GE:
|
466
|
+
|
528
467
|
def function(value):
|
529
468
|
return value is not None and value >= filter_values
|
530
469
|
|
531
470
|
elif report_filter.operator == constants.IS_NULL:
|
471
|
+
|
532
472
|
def function(value):
|
533
473
|
return value is None or value == ''
|
534
474
|
|
535
475
|
elif report_filter.operator == constants.CONTAINS:
|
536
|
-
assert isinstance(filter_values, str), type(
|
537
|
-
filter_values
|
538
|
-
)
|
476
|
+
assert isinstance(filter_values, str), type(filter_values)
|
539
477
|
|
540
478
|
if report_filter.case_sensitive:
|
479
|
+
|
541
480
|
def function(value):
|
542
481
|
return value is not None and filter_values in value
|
543
482
|
else:
|
483
|
+
|
544
484
|
def function(value):
|
545
|
-
return value is not None and any(
|
546
|
-
v.lower() in value
|
547
|
-
for v in filter_values
|
548
|
-
)
|
485
|
+
return value is not None and any(v.lower() in value for v in filter_values)
|
549
486
|
|
550
487
|
elif report_filter.operator == constants.STARTS_WITH:
|
551
|
-
assert isinstance(filter_values, str), type(
|
552
|
-
filter_values
|
553
|
-
)
|
488
|
+
assert isinstance(filter_values, str), type(filter_values)
|
554
489
|
|
555
490
|
if report_filter.case_sensitive:
|
491
|
+
|
556
492
|
def function(value):
|
557
493
|
return value is not None and value.startswith(filter_values)
|
558
494
|
else:
|
495
|
+
|
559
496
|
def function(value):
|
560
497
|
return value is not None and value.lower().startswith(filter_values.lower())
|
561
498
|
|
562
499
|
elif report_filter.operator == constants.ENDS_WITH:
|
563
|
-
assert isinstance(filter_values, str), type(
|
564
|
-
filter_values
|
565
|
-
)
|
500
|
+
assert isinstance(filter_values, str), type(filter_values)
|
566
501
|
|
567
502
|
if report_filter.case_sensitive:
|
503
|
+
|
568
504
|
def function(value):
|
569
505
|
return value is not None and value.endswith(filter_values)
|
570
506
|
else:
|
507
|
+
|
571
508
|
def function(value):
|
572
509
|
return value is not None and value.lower().endswith(filter_values.lower())
|
573
510
|
|
574
511
|
elif report_filter.operator == constants.BETWEEN:
|
575
512
|
if report_filter.case_sensitive:
|
513
|
+
|
576
514
|
def function(value):
|
577
|
-
return
|
578
|
-
value is not None and
|
579
|
-
filter_values[0] <= value <= filter_values[1]
|
580
|
-
)
|
515
|
+
return value is not None and filter_values[0] <= value <= filter_values[1]
|
581
516
|
else:
|
517
|
+
|
582
518
|
def function(value):
|
583
519
|
if isinstance(value, str):
|
584
520
|
value = value.lower()
|
@@ -586,28 +522,22 @@ class _DataFilterer:
|
|
586
522
|
else:
|
587
523
|
values = filter_values
|
588
524
|
|
589
|
-
return
|
590
|
-
value is not None and
|
591
|
-
values[0] <= value <= values[1]
|
592
|
-
)
|
525
|
+
return value is not None and values[0] <= value <= values[1]
|
593
526
|
|
594
527
|
elif report_filter.operator == constants.IN:
|
595
528
|
assert isinstance(filter_values, tuple), type(filter_values)
|
596
529
|
|
597
530
|
if report_filter.case_sensitive:
|
531
|
+
|
598
532
|
def function(value):
|
599
533
|
return value in filter_values
|
600
534
|
else:
|
535
|
+
|
601
536
|
def function(value):
|
602
537
|
return value.lower() in (v.lower() for v in filter_values)
|
603
538
|
|
604
539
|
else:
|
605
|
-
raise FilterError(
|
606
|
-
report_filter,
|
607
|
-
'Неподдерживаемый оператор ({})'.format(
|
608
|
-
report_filter.operator
|
609
|
-
)
|
610
|
-
)
|
540
|
+
raise FilterError(report_filter, 'Неподдерживаемый оператор ({})'.format(report_filter.operator))
|
611
541
|
|
612
542
|
if report_filter.exclude:
|
613
543
|
return lambda value: not function(value)
|
@@ -626,14 +556,11 @@ class _DataFilterer:
|
|
626
556
|
втором случае --- будут удалены записи во внутренних блоках.
|
627
557
|
"""
|
628
558
|
filter_functions = {
|
629
|
-
report_filter.column_id: self._get_function_for_filter(
|
630
|
-
report_filter
|
631
|
-
)
|
559
|
+
report_filter.column_id: self._get_function_for_filter(report_filter)
|
632
560
|
for report_filter in self.filters_by_id.values()
|
633
561
|
}
|
634
562
|
filter_functions_by_column = tuple(
|
635
|
-
filter_functions.get(report_column.pk)
|
636
|
-
for report_column in self._report_columns
|
563
|
+
filter_functions.get(report_column.pk) for report_column in self._report_columns
|
637
564
|
)
|
638
565
|
|
639
566
|
def filter_function(row_data, column_functions=None):
|
@@ -648,8 +575,7 @@ class _DataFilterer:
|
|
648
575
|
column_functions = column_functions[cell_width:]
|
649
576
|
|
650
577
|
if is_block(cell):
|
651
|
-
filtered_block = _filter_block_or_row(
|
652
|
-
cell, column_filter_functions)
|
578
|
+
filtered_block = _filter_block_or_row(cell, column_filter_functions)
|
653
579
|
if filtered_block is None:
|
654
580
|
return None
|
655
581
|
result.append(filtered_block)
|
@@ -657,10 +583,7 @@ class _DataFilterer:
|
|
657
583
|
# Простое значение (не строка или блок)
|
658
584
|
assert not is_row(cell), cell
|
659
585
|
column_filter_function = column_filter_functions[0]
|
660
|
-
if (
|
661
|
-
column_filter_function and
|
662
|
-
not column_filter_function(cell)
|
663
|
-
):
|
586
|
+
if column_filter_function and not column_filter_function(cell):
|
664
587
|
return None
|
665
588
|
result.append(cell)
|
666
589
|
|
@@ -670,8 +593,7 @@ class _DataFilterer:
|
|
670
593
|
"""Возвращет отфильтрованный блок/строку или None."""
|
671
594
|
if is_row(block_or_row):
|
672
595
|
return filter_function(block_or_row, column_filter_functions)
|
673
|
-
filtered = [_filter_block_or_row(item, column_filter_functions)
|
674
|
-
for item in block_or_row]
|
596
|
+
filtered = [_filter_block_or_row(item, column_filter_functions) for item in block_or_row]
|
675
597
|
filtered = [item for item in filtered if item is not None]
|
676
598
|
return filtered or None
|
677
599
|
|
@@ -722,9 +644,7 @@ class _DataSorter:
|
|
722
644
|
столбцы были добавлены в шаблон отчета до того, как были удалены
|
723
645
|
из моделей Системы).
|
724
646
|
"""
|
725
|
-
assert isinstance(report_template, ReportTemplate), type(
|
726
|
-
report_template
|
727
|
-
)
|
647
|
+
assert isinstance(report_template, ReportTemplate), type(report_template)
|
728
648
|
|
729
649
|
self._report_template = report_template
|
730
650
|
self._ignored_columns_ids = ignored_columns_ids
|
@@ -732,11 +652,11 @@ class _DataSorter:
|
|
732
652
|
@cached_property
|
733
653
|
def _params(self):
|
734
654
|
data = enumerate(
|
735
|
-
self._report_template.columns.exclude(
|
736
|
-
|
737
|
-
).order_by(
|
655
|
+
self._report_template.columns.exclude(id__in=self._ignored_columns_ids)
|
656
|
+
.order_by(
|
738
657
|
'index',
|
739
|
-
)
|
658
|
+
)
|
659
|
+
.values_list(
|
740
660
|
'sorting__index',
|
741
661
|
'sorting__direction',
|
742
662
|
)
|
@@ -775,10 +695,7 @@ class _DataSorter:
|
|
775
695
|
values[sort_index] = _OrderInverter(cell)
|
776
696
|
index += 1
|
777
697
|
|
778
|
-
result = tuple(
|
779
|
-
values[sort_index]
|
780
|
-
for sort_index in sorted(values)
|
781
|
-
)
|
698
|
+
result = tuple(values[sort_index] for sort_index in sorted(values))
|
782
699
|
|
783
700
|
return result
|
784
701
|
|
@@ -806,8 +723,7 @@ class _DataSorter:
|
|
806
723
|
index += 1
|
807
724
|
|
808
725
|
nullable_rows = filter(self._is_row_nullable, rows)
|
809
|
-
non_nullable_rows = filter(
|
810
|
-
lambda _row: not self._is_row_nullable(_row), rows)
|
726
|
+
non_nullable_rows = filter(lambda _row: not self._is_row_nullable(_row), rows)
|
811
727
|
|
812
728
|
sorted_rows = sorted(
|
813
729
|
non_nullable_rows,
|
@@ -870,15 +786,12 @@ class DataLoader:
|
|
870
786
|
(
|
871
787
|
('СДЮШОР1', 'Бокс'),
|
872
788
|
('СДЮШОР1', 'Фехтование'),
|
873
|
-
)
|
789
|
+
),
|
874
790
|
)
|
875
791
|
"""
|
876
792
|
|
877
|
-
def __init__(self, report_template, data_source, report_columns,
|
878
|
-
|
879
|
-
assert isinstance(report_template, ReportTemplate), type(
|
880
|
-
report_template
|
881
|
-
)
|
793
|
+
def __init__(self, report_template, data_source, report_columns, ignored_columns_ids, user):
|
794
|
+
assert isinstance(report_template, ReportTemplate), type(report_template)
|
882
795
|
self._report_template = report_template
|
883
796
|
self._data_source = data_source
|
884
797
|
self._report_columns = report_columns
|
@@ -889,9 +802,7 @@ class DataLoader:
|
|
889
802
|
def _get_column_count(columns):
|
890
803
|
# Для иерархии столбцов возвращает количество занимаемых столбцов.
|
891
804
|
if columns:
|
892
|
-
return sum(map(
|
893
|
-
DataLoader._get_column_count, columns.values()
|
894
|
-
))
|
805
|
+
return sum(map(DataLoader._get_column_count, columns.values()))
|
895
806
|
else:
|
896
807
|
return 1
|
897
808
|
|
@@ -924,9 +835,9 @@ class DataLoader:
|
|
924
835
|
attr_value = getattr(obj, attr_name)
|
925
836
|
except AttributeError:
|
926
837
|
if (
|
927
|
-
hasattr(obj, 'report_constructor_params')
|
928
|
-
'extra' in obj.report_constructor_params
|
929
|
-
attr_name in obj.report_constructor_params['extra']
|
838
|
+
hasattr(obj, 'report_constructor_params')
|
839
|
+
and 'extra' in obj.report_constructor_params
|
840
|
+
and attr_name in obj.report_constructor_params['extra']
|
930
841
|
):
|
931
842
|
# Дополнительное поле.
|
932
843
|
extra = obj.report_constructor_params['extra']
|
@@ -940,34 +851,24 @@ class DataLoader:
|
|
940
851
|
else:
|
941
852
|
raise
|
942
853
|
|
943
|
-
if (
|
944
|
-
attr_value
|
945
|
-
isinstance(field, (models.BooleanField,
|
946
|
-
models.NullBooleanField))
|
947
|
-
):
|
948
|
-
attr_value = (
|
949
|
-
TRUE if attr_value else FALSE
|
950
|
-
)
|
854
|
+
if attr_value is not None and isinstance(field, (models.BooleanField, models.NullBooleanField)):
|
855
|
+
attr_value = TRUE if attr_value else FALSE
|
951
856
|
else:
|
952
857
|
attr_value = obj
|
953
858
|
descriptor = None
|
954
859
|
|
955
860
|
# Обратная связь или M2M. Такие данные выводятся в виде кортежа.
|
956
|
-
if (
|
957
|
-
|
958
|
-
(
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
isinstance(field, models.ManyToManyField) and
|
963
|
-
isinstance(attr_value, Manager)
|
964
|
-
)
|
861
|
+
if attr_name and (
|
862
|
+
isinstance(field, ForeignObjectRel)
|
863
|
+
and hasattr(descriptor, 'related_manager_cls')
|
864
|
+
and isinstance(attr_value, descriptor.related_manager_cls)
|
865
|
+
or isinstance(field, models.ManyToManyField)
|
866
|
+
and isinstance(attr_value, Manager)
|
965
867
|
):
|
966
868
|
objects = attr_value.all()
|
967
869
|
if objects:
|
968
870
|
related_obj_data_gen = (
|
969
|
-
list(DataLoader._get_object_data(related_obj, None, nested))
|
970
|
-
for related_obj in objects
|
871
|
+
list(DataLoader._get_object_data(related_obj, None, nested)) for related_obj in objects
|
971
872
|
)
|
972
873
|
yield list(itertools.takewhile(bool, related_obj_data_gen))
|
973
874
|
else:
|
@@ -977,9 +878,7 @@ class DataLoader:
|
|
977
878
|
elif nested:
|
978
879
|
if attr_value:
|
979
880
|
for k, v in nested.items():
|
980
|
-
for object_data in (
|
981
|
-
DataLoader._get_object_data(attr_value, k, v)
|
982
|
-
):
|
881
|
+
for object_data in DataLoader._get_object_data(attr_value, k, v):
|
983
882
|
yield object_data
|
984
883
|
else:
|
985
884
|
for _ in range(DataLoader._get_column_count(nested)):
|
@@ -991,22 +890,14 @@ class DataLoader:
|
|
991
890
|
inner_values = []
|
992
891
|
for inner_value in attr_value:
|
993
892
|
if getattr(field.base_field, 'flatchoices', False):
|
994
|
-
inner_values.append(
|
995
|
-
DataLoader._get_field_display(
|
996
|
-
field.base_field, inner_value
|
997
|
-
)
|
998
|
-
)
|
893
|
+
inner_values.append(DataLoader._get_field_display(field.base_field, inner_value))
|
999
894
|
else:
|
1000
895
|
inner_values.append(inner_value)
|
1001
|
-
yield list(
|
1002
|
-
(str(value),) for value in inner_values
|
1003
|
-
)
|
896
|
+
yield list((str(value),) for value in inner_values)
|
1004
897
|
|
1005
898
|
# Поле с choices.
|
1006
899
|
elif getattr(field, 'flatchoices', False):
|
1007
|
-
yield DataLoader._get_field_display(
|
1008
|
-
field, attr_value
|
1009
|
-
)
|
900
|
+
yield DataLoader._get_field_display(field, attr_value)
|
1010
901
|
|
1011
902
|
# Поле с данными.
|
1012
903
|
else:
|
@@ -1015,10 +906,7 @@ class DataLoader:
|
|
1015
906
|
@cached_property
|
1016
907
|
def _data_filterer(self):
|
1017
908
|
"""Фильтратор данных отчета."""
|
1018
|
-
return _DataFilterer(
|
1019
|
-
self._report_template, self._data_source, self._report_columns,
|
1020
|
-
self._ignored_columns_ids
|
1021
|
-
)
|
909
|
+
return _DataFilterer(self._report_template, self._data_source, self._report_columns, self._ignored_columns_ids)
|
1022
910
|
|
1023
911
|
@cached_property
|
1024
912
|
def _data_aggregator(self):
|
@@ -1027,30 +915,27 @@ class DataLoader:
|
|
1027
915
|
|
1028
916
|
def _available_units_filter(self, query):
|
1029
917
|
"""Фильтратор данных отчета по доступности учреждений."""
|
1030
|
-
return self._data_source.add_source_filter(
|
1031
|
-
query, self._report_template.include_available_units,
|
1032
|
-
self._user
|
1033
|
-
)
|
918
|
+
return self._data_source.add_source_filter(query, self._report_template.include_available_units, self._user)
|
1034
919
|
|
1035
920
|
def _get_objects(self):
|
1036
921
|
result = self._data_source.model.objects.all()
|
1037
922
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
1038
923
|
# Добавление фильтров в запрос.
|
1039
924
|
|
1040
|
-
if
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
925
|
+
if (
|
926
|
+
ReportFilter.objects.filter(
|
927
|
+
column__report_template=self._report_template,
|
928
|
+
)
|
929
|
+
.exclude(column_id__in=self._ignored_columns_ids)
|
930
|
+
.exists()
|
931
|
+
):
|
1045
932
|
# Является ли модель древовидной(mptt - Modified Preorder Tree Traversal)
|
1046
933
|
if hasattr(self._data_source.model, '_mptt_meta'):
|
1047
|
-
result = result.filter(
|
1048
|
-
self.
|
1049
|
-
)
|
934
|
+
result = result.filter(self._data_filterer.get_orm_filters()).distinct(
|
935
|
+
self._data_source.model._mptt_meta.tree_id_attr
|
936
|
+
)
|
1050
937
|
else:
|
1051
|
-
result = result.filter(
|
1052
|
-
self._data_filterer.get_orm_filters()
|
1053
|
-
).distinct('pk')
|
938
|
+
result = result.filter(self._data_filterer.get_orm_filters()).distinct('pk')
|
1054
939
|
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
1055
940
|
# Добавление параметров включения вложенных учреждений.
|
1056
941
|
|
@@ -1063,9 +948,7 @@ class DataLoader:
|
|
1063
948
|
filter_function = self._data_filterer.get_filter_function()
|
1064
949
|
|
1065
950
|
for obj in self._get_objects():
|
1066
|
-
row_data = list(
|
1067
|
-
DataLoader._get_object_data(obj, None, columns_hierarchy)
|
1068
|
-
)
|
951
|
+
row_data = list(DataLoader._get_object_data(obj, None, columns_hierarchy))
|
1069
952
|
if row_data and any(row_data):
|
1070
953
|
row_data = filter_function(row_data)
|
1071
954
|
if row_data:
|
@@ -1073,16 +956,16 @@ class DataLoader:
|
|
1073
956
|
yield row_data
|
1074
957
|
|
1075
958
|
def __iter__(self):
|
1076
|
-
column_names =
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
959
|
+
column_names = (
|
960
|
+
self._report_template.columns.filter(
|
961
|
+
visible=True,
|
962
|
+
)
|
963
|
+
.exclude(pk__in=self._ignored_columns_ids)
|
964
|
+
.values_list('name', flat=True)
|
965
|
+
)
|
1081
966
|
|
1082
967
|
if not column_names:
|
1083
|
-
raise ReportConstructorException(
|
1084
|
-
'В шаблоне нет ни одного отображаемого столбца.'
|
1085
|
-
)
|
968
|
+
raise ReportConstructorException('В шаблоне нет ни одного отображаемого столбца.')
|
1086
969
|
|
1087
970
|
columns_hierarchy = get_columns_hierarchy(*column_names)
|
1088
971
|
|
@@ -1108,9 +991,7 @@ class ReportBuilderBase(metaclass=abc.ABCMeta):
|
|
1108
991
|
|
1109
992
|
:param str file_path: Путь к файлу отчета.
|
1110
993
|
"""
|
1111
|
-
assert isinstance(report_template, ReportTemplate), type(
|
1112
|
-
report_template
|
1113
|
-
)
|
994
|
+
assert isinstance(report_template, ReportTemplate), type(report_template)
|
1114
995
|
|
1115
996
|
if report_template.data_source_name not in registry:
|
1116
997
|
raise DataSourceParamsNotFound(report_template.data_source_name)
|
@@ -1133,11 +1014,7 @@ class ReportBuilderBase(metaclass=abc.ABCMeta):
|
|
1133
1014
|
|
1134
1015
|
:rtype: tuple
|
1135
1016
|
"""
|
1136
|
-
return tuple(
|
1137
|
-
self._report_template.columns.exclude(
|
1138
|
-
pk__in=self._ignored_columns_ids
|
1139
|
-
)
|
1140
|
-
)
|
1017
|
+
return tuple(self._report_template.columns.exclude(pk__in=self._ignored_columns_ids))
|
1141
1018
|
|
1142
1019
|
@cached_property
|
1143
1020
|
def _ignored_columns_ids(self):
|
@@ -1146,8 +1023,7 @@ class ReportBuilderBase(metaclass=abc.ABCMeta):
|
|
1146
1023
|
:rtype: set
|
1147
1024
|
"""
|
1148
1025
|
ignored_columns = set()
|
1149
|
-
for col_id, col_name in self._report_template.columns.values_list(
|
1150
|
-
'id', 'name'):
|
1026
|
+
for col_id, col_name in self._report_template.columns.values_list('id', 'name'):
|
1151
1027
|
if self._data_source.is_column_ignored(col_name):
|
1152
1028
|
ignored_columns.add(col_id)
|
1153
1029
|
|
@@ -1161,20 +1037,21 @@ class ReportBuilderBase(metaclass=abc.ABCMeta):
|
|
1161
1037
|
"""
|
1162
1038
|
return list(
|
1163
1039
|
DataLoader(
|
1164
|
-
self._report_template, self._data_source, self._report_columns,
|
1165
|
-
self._ignored_columns_ids, self._user
|
1040
|
+
self._report_template, self._data_source, self._report_columns, self._ignored_columns_ids, self._user
|
1166
1041
|
)
|
1167
1042
|
)
|
1168
1043
|
|
1169
1044
|
@cached_property
|
1170
1045
|
def _workbook(self):
|
1171
1046
|
"""Книга Excel, в которой формируется отчет."""
|
1172
|
-
result = Workbook(
|
1173
|
-
|
1174
|
-
|
1047
|
+
result = Workbook(
|
1048
|
+
self._file_path,
|
1049
|
+
dict(
|
1050
|
+
default_date_format='dd.mm.yyyy',
|
1051
|
+
),
|
1052
|
+
)
|
1175
1053
|
|
1176
|
-
for cell_format in (result.default_date_format,
|
1177
|
-
result.default_url_format):
|
1054
|
+
for cell_format in (result.default_date_format, result.default_url_format):
|
1178
1055
|
cell_format.set_border()
|
1179
1056
|
cell_format.set_align('vcenter')
|
1180
1057
|
|
@@ -1267,9 +1144,8 @@ class ColumnCounter(BaseColumnAggregator):
|
|
1267
1144
|
title = 'Количество'
|
1268
1145
|
|
1269
1146
|
def __init__(self, column_index, by_value, total, **kwargs):
|
1270
|
-
super(ColumnCounter, self).__init__(
|
1271
|
-
|
1272
|
-
)
|
1147
|
+
super(ColumnCounter, self).__init__(column_index, by_value, total, **kwargs)
|
1148
|
+
|
1273
1149
|
# Требуется ли вывод в итоге количества уникальных значений.
|
1274
1150
|
self.__is_total_unique = kwargs.get('total_unique', False)
|
1275
1151
|
|
@@ -1318,21 +1194,14 @@ def get_column_aggregator_info(column):
|
|
1318
1194
|
:return: Тип агрегатора, (промежуточный итог, итог, количество уникальных)
|
1319
1195
|
:rtype: tuple
|
1320
1196
|
"""
|
1321
|
-
if (
|
1322
|
-
column.by_value == BY_VALUE_COUNT or
|
1323
|
-
column.total in (TOTAL_COUNT, TOTAL_UNIQUE_COUNT)
|
1324
|
-
):
|
1197
|
+
if column.by_value == BY_VALUE_COUNT or column.total in (TOTAL_COUNT, TOTAL_UNIQUE_COUNT):
|
1325
1198
|
return COUNT, (
|
1326
1199
|
column.by_value == BY_VALUE_COUNT,
|
1327
1200
|
column.total == TOTAL_COUNT,
|
1328
|
-
column.total == TOTAL_UNIQUE_COUNT
|
1201
|
+
column.total == TOTAL_UNIQUE_COUNT,
|
1329
1202
|
)
|
1330
1203
|
elif column.by_value == BY_VALUE_SUM or column.total == TOTAL_SUM:
|
1331
|
-
return SUM, (
|
1332
|
-
column.by_value == BY_VALUE_SUM,
|
1333
|
-
column.total == TOTAL_SUM,
|
1334
|
-
None
|
1335
|
-
)
|
1204
|
+
return SUM, (column.by_value == BY_VALUE_SUM, column.total == TOTAL_SUM, None)
|
1336
1205
|
else:
|
1337
1206
|
return None, (None, None, None)
|
1338
1207
|
|
@@ -1353,16 +1222,11 @@ class DataAggregator:
|
|
1353
1222
|
|
1354
1223
|
def set_aggregator(self, aggregator):
|
1355
1224
|
"""Добавляет агрегатор."""
|
1356
|
-
self._aggregators[aggregator.type] = dict(
|
1357
|
-
cls=aggregator,
|
1358
|
-
instances=dict()
|
1359
|
-
)
|
1225
|
+
self._aggregators[aggregator.type] = dict(cls=aggregator, instances=dict())
|
1360
1226
|
|
1361
1227
|
def get_column_aggregator(self, column, column_idx):
|
1362
1228
|
"""Возвращает агрегатор для колонки."""
|
1363
|
-
aggregator_type, (by_value, total, total_unique) = (
|
1364
|
-
get_column_aggregator_info(column)
|
1365
|
-
)
|
1229
|
+
aggregator_type, (by_value, total, total_unique) = get_column_aggregator_info(column)
|
1366
1230
|
aggregator = self._aggregators.get(aggregator_type)
|
1367
1231
|
if not aggregator:
|
1368
1232
|
return
|
@@ -1413,7 +1277,8 @@ class DataAggregator:
|
|
1413
1277
|
aggregator.column_index,
|
1414
1278
|
aggregator.data.items(),
|
1415
1279
|
)
|
1416
|
-
for aggregator in aggregators
|
1280
|
+
for aggregator in aggregators
|
1281
|
+
if aggregator.is_by_value
|
1417
1282
|
)
|
1418
1283
|
for title, col_idx, data in aggregators_data:
|
1419
1284
|
for idx, (value, value_data) in enumerate(data):
|
@@ -1423,24 +1288,16 @@ class DataAggregator:
|
|
1423
1288
|
row_data = self.get_empty_row()
|
1424
1289
|
rows.append(row_data)
|
1425
1290
|
|
1426
|
-
row_data[col_idx] = (
|
1427
|
-
'{} "{}": {}'.format(title, value, value_data)
|
1428
|
-
)
|
1291
|
+
row_data[col_idx] = '{} "{}": {}'.format(title, value, value_data)
|
1429
1292
|
|
1430
1293
|
def _extend_rows_by_count(self, rows):
|
1431
1294
|
"""Добавляет строки с количеством элементов."""
|
1432
|
-
counters = sorted(
|
1433
|
-
self._aggregators[COUNT]['instances'].values(),
|
1434
|
-
key=lambda c: c.column_index
|
1435
|
-
)
|
1295
|
+
counters = sorted(self._aggregators[COUNT]['instances'].values(), key=lambda c: c.column_index)
|
1436
1296
|
self._extend_rows(counters, rows)
|
1437
1297
|
|
1438
1298
|
def _extend_rows_by_sum(self, rows):
|
1439
1299
|
"""Добавляет строки с суммой элементов."""
|
1440
|
-
summators = sorted(
|
1441
|
-
self._aggregators[SUM]['instances'].values(),
|
1442
|
-
key=lambda c: c.column_index
|
1443
|
-
)
|
1300
|
+
summators = sorted(self._aggregators[SUM]['instances'].values(), key=lambda c: c.column_index)
|
1444
1301
|
self._extend_rows(summators, rows)
|
1445
1302
|
|
1446
1303
|
def get_total_row(self):
|
@@ -1449,14 +1306,9 @@ class DataAggregator:
|
|
1449
1306
|
for aggregator in self._aggregators.values():
|
1450
1307
|
for instance in aggregator['instances'].values():
|
1451
1308
|
if instance.is_total:
|
1452
|
-
row[instance.column_index] = 'Итог({}): {}'.format(
|
1453
|
-
instance.title,
|
1454
|
-
instance.total
|
1455
|
-
)
|
1309
|
+
row[instance.column_index] = 'Итог({}): {}'.format(instance.title, instance.total)
|
1456
1310
|
elif instance.is_total_unique:
|
1457
|
-
row[instance.column_index] = (
|
1458
|
-
'Итог(Уникальных): {}'.format(instance.total_unique)
|
1459
|
-
)
|
1311
|
+
row[instance.column_index] = 'Итог(Уникальных): {}'.format(instance.total_unique)
|
1460
1312
|
|
1461
1313
|
return row
|
1462
1314
|
|