educommon 3.13.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 +4 -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.0.dist-info → educommon-3.13.2.dist-info}/METADATA +26 -14
- educommon-3.13.2.dist-info/RECORD +354 -0
- educommon/utils/patches.py +0 -27
- educommon/version.conf +0 -11
- educommon-3.13.0.dist-info/RECORD +0 -357
- educommon-3.13.0.dist-info/dependency_links.txt +0 -1
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +0 -0
- {educommon-3.13.0.dist-info → educommon-3.13.2.dist-info}/top_level.txt +0 -0
educommon/m3/extensions/ui.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Расширение поведения интерфейсов."""
|
2
|
+
|
2
3
|
from m3_ext.ui import (
|
3
4
|
all_components as ext,
|
4
5
|
)
|
@@ -9,8 +10,7 @@ from objectpack.ui import (
|
|
9
10
|
|
10
11
|
|
11
12
|
class BaseEditWinExtender:
|
12
|
-
"""
|
13
|
-
Базовый объект для расширения окон редактирования.
|
13
|
+
"""Базовый объект для расширения окон редактирования.
|
14
14
|
|
15
15
|
``_extend_edit_win`` - добавление и размещение контролов
|
16
16
|
``bind_to_object`` - заполнение объекта данными из полей формы
|
@@ -31,39 +31,31 @@ class BaseEditWinExtender:
|
|
31
31
|
self._extend_edit_win()
|
32
32
|
|
33
33
|
def _extend_edit_win(self):
|
34
|
-
"""
|
35
|
-
Расширение формы окна.
|
34
|
+
"""Расширение формы окна.
|
36
35
|
|
37
36
|
..code::
|
38
37
|
|
39
38
|
for fld in self.model_fields_to_controls(self.model_fields):
|
40
39
|
self._win.form.items.append(fld)
|
41
|
-
|
42
40
|
"""
|
43
41
|
raise NotImplementedError()
|
44
42
|
|
45
43
|
def model_fields_to_controls(self, fields):
|
46
44
|
"""Шорткат для генерации контролов."""
|
47
45
|
assert self.model, 'No model defined in Extender!'
|
48
|
-
return model_fields_to_controls(
|
49
|
-
self.model,
|
50
|
-
self._win,
|
51
|
-
field_list=fields,
|
52
|
-
model_register=self.model_register
|
53
|
-
)
|
46
|
+
return model_fields_to_controls(self.model, self._win, field_list=fields, model_register=self.model_register)
|
54
47
|
|
55
48
|
# -------------------------------------------------------------------------
|
56
49
|
# Биндинг из формы в объект
|
57
50
|
|
58
51
|
@classmethod
|
59
52
|
def set_value(cls, instance, field_names, value):
|
60
|
-
"""
|
61
|
-
Установка значения поля (полей).
|
53
|
+
"""Установка значения поля (полей).
|
62
54
|
|
63
55
|
:param instance: инстанс модели, которая расширяет основную ``model``
|
64
56
|
:param list field_names: список связаных полей (либо одно поле)
|
65
57
|
:raise: DoesNotExist если предварительно не инстанцировали зависимые
|
66
|
-
сущности (для случая связанных полей)
|
58
|
+
сущности (для случая связанных полей).
|
67
59
|
"""
|
68
60
|
if len(field_names) == 1:
|
69
61
|
# связанных полей нет
|
@@ -76,15 +68,13 @@ class BaseEditWinExtender:
|
|
76
68
|
|
77
69
|
@classmethod
|
78
70
|
def bind_to_object(cls, instance, context):
|
79
|
-
"""
|
80
|
-
Заполнение полей ``model_fields`` модели instance по полям формы.
|
71
|
+
"""Заполнение полей ``model_fields`` модели instance по полям формы.
|
81
72
|
|
82
73
|
:param instance: инстанс модели, которая расширяет основную ``model``
|
83
74
|
:param context: контекст
|
84
75
|
:type context: m3.actions.context.DeclarativeActionContext
|
85
76
|
"""
|
86
|
-
assert cls.model_fields is not None,
|
87
|
-
'No model_fields defined in Extender')
|
77
|
+
assert cls.model_fields is not None, 'No model_fields defined in Extender'
|
88
78
|
|
89
79
|
for field_name in cls.model_fields:
|
90
80
|
try:
|
@@ -99,13 +89,11 @@ class BaseEditWinExtender:
|
|
99
89
|
# Биндинг из объекта в форму
|
100
90
|
|
101
91
|
def bind_from_object(self, instance):
|
102
|
-
"""
|
103
|
-
Заполнение полей ``model_fields`` формы по полям модели instance.
|
92
|
+
"""Заполнение полей ``model_fields`` формы по полям модели instance.
|
104
93
|
|
105
94
|
:param instance: инстанс модели, которая расширяет основную ``model``
|
106
95
|
"""
|
107
|
-
assert self.model_fields is not None,
|
108
|
-
'No model_fields defined in Extender')
|
96
|
+
assert self.model_fields is not None, 'No model_fields defined in Extender'
|
109
97
|
for name in self.model_fields:
|
110
98
|
field = self._win.find_by_name(name)
|
111
99
|
field_names = field.name.split('.')
|
@@ -114,8 +102,7 @@ class BaseEditWinExtender:
|
|
114
102
|
self._set_value_to_field(field, value)
|
115
103
|
|
116
104
|
def _get_value(self, instance, field_names):
|
117
|
-
"""
|
118
|
-
Получение значение поля (полей).
|
105
|
+
"""Получение значение поля (полей).
|
119
106
|
|
120
107
|
:param instance: инстанс модели, которая расширяет основную ``model``
|
121
108
|
:param list field_names: список связаных полей (либо одно поле)
|
@@ -132,8 +119,7 @@ class BaseEditWinExtender:
|
|
132
119
|
|
133
120
|
@staticmethod
|
134
121
|
def _set_value_to_field(field, value):
|
135
|
-
"""
|
136
|
-
Установка значения в поле.
|
122
|
+
"""Установка значения в поле.
|
137
123
|
|
138
124
|
:param field: наследник BaseExtField
|
139
125
|
:param value: значение для установки в поле
|
@@ -145,22 +131,18 @@ class BaseEditWinExtender:
|
|
145
131
|
if isinstance(field, ext.ExtMultiSelectField):
|
146
132
|
field.value = pack.model.get_serialized_values(value)
|
147
133
|
else:
|
148
|
-
field.default_text = pack.get_display_text(
|
149
|
-
value, field.display_field)
|
134
|
+
field.default_text = pack.get_display_text(value, field.display_field)
|
150
135
|
elif isinstance(field, ext.ExtCheckBox):
|
151
136
|
field.checked = bool(value)
|
152
137
|
|
153
138
|
def set_params(self, params):
|
154
|
-
"""
|
155
|
-
Установка параметров компонентам.
|
139
|
+
"""Установка параметров компонентам.
|
156
140
|
|
157
141
|
Выполняется по завершению создания компонент, размещению на форме и
|
158
142
|
после биндинга значений в форму.
|
159
143
|
|
160
144
|
..code::
|
161
145
|
|
162
|
-
self._win.field__some.make_read_only(
|
163
|
-
access_off=params['instance'].date > datetime.date.today()
|
164
|
-
)
|
146
|
+
self._win.field__some.make_read_only(access_off=params['instance'].date > datetime.date.today())
|
165
147
|
"""
|
166
148
|
pass
|
@@ -29,6 +29,7 @@ with TransactionCM('user_import'):
|
|
29
29
|
user.set_password(pwd)
|
30
30
|
user.save()
|
31
31
|
"""
|
32
|
+
|
32
33
|
from functools import (
|
33
34
|
wraps,
|
34
35
|
)
|
@@ -58,27 +59,25 @@ def _prepare_state():
|
|
58
59
|
if not hasattr(_state, 'situation'):
|
59
60
|
_reset_state()
|
60
61
|
|
62
|
+
|
61
63
|
_reset_state()
|
62
64
|
|
63
65
|
|
64
66
|
class AbortTransaction(Exception):
|
65
|
-
"""
|
66
|
-
|
67
|
+
"""Исключение, прерывающее текущий CM (SavePointCM/TransactionCM).
|
68
|
+
|
67
69
|
Поймав это исключение CM откатывает изменения,
|
68
70
|
произошедшие с момента входа в него и корректно завершается.
|
69
71
|
"""
|
72
|
+
|
70
73
|
pass
|
71
74
|
|
72
75
|
|
73
76
|
class SavePointCM:
|
74
|
-
"""
|
75
|
-
Context Manager создающий на время своего действия savepoint
|
76
|
-
"""
|
77
|
+
"""Context Manager создающий на время своего действия savepoint."""
|
77
78
|
|
78
79
|
def __init__(self):
|
79
|
-
assert _state.situation,
|
80
|
-
'Must be nested in TransactionCM!'
|
81
|
-
)
|
80
|
+
assert _state.situation, 'Must be nested in TransactionCM!'
|
82
81
|
cookie = uuid4()
|
83
82
|
_state.cookies.append(cookie)
|
84
83
|
self._cookie = cookie
|
@@ -103,15 +102,11 @@ class SavePointCM:
|
|
103
102
|
|
104
103
|
|
105
104
|
class TransactionCM:
|
106
|
-
"""
|
107
|
-
ContextManager создающий "ручную" транзакцию
|
108
|
-
"""
|
105
|
+
"""ContextManager создающий "ручную" транзакцию."""
|
109
106
|
|
110
107
|
def __init__(self, situation, rollback_all=True, using=None):
|
111
108
|
_prepare_state()
|
112
|
-
assert not _state.situation,
|
113
|
-
'Nested contexts not supported!'
|
114
|
-
)
|
109
|
+
assert not _state.situation, 'Nested contexts not supported!'
|
115
110
|
_reset_state()
|
116
111
|
_state.situation = self._situation = situation
|
117
112
|
|
@@ -126,10 +121,10 @@ class TransactionCM:
|
|
126
121
|
try:
|
127
122
|
if ex_type is None:
|
128
123
|
try:
|
129
|
-
for
|
124
|
+
for task, cookie in _state.task_queue:
|
130
125
|
if cookie not in _state.rolled_back:
|
131
126
|
task()
|
132
|
-
except Exception
|
127
|
+
except Exception:
|
133
128
|
transaction.rollback(self._using)
|
134
129
|
_reset_state()
|
135
130
|
raise
|
@@ -149,22 +144,25 @@ class TransactionCM:
|
|
149
144
|
|
150
145
|
|
151
146
|
def delay_in_situations(*situations):
|
152
|
-
"""
|
153
|
-
|
147
|
+
"""Оборачивает функцию и возвращает функцию-обработчик сигнала Django.
|
148
|
+
|
154
149
|
В контексте одной из ситуаций, перечисленных в @situations
|
155
150
|
выполнение функции, возвращённой оборачиваемой функцией,
|
156
151
|
будет отложено до успешного завершения TransactionCM, создавшего ситуацию.
|
157
152
|
"""
|
153
|
+
|
158
154
|
def wrapper(fn):
|
159
155
|
@wraps(fn)
|
160
156
|
def inner(*args, **kwargs):
|
161
157
|
cont = fn(*args, **kwargs)
|
162
|
-
assert callable(cont),
|
158
|
+
assert callable(cont), 'Task must return the callable object!'
|
163
159
|
situation = getattr(_state, 'situation', None)
|
164
160
|
if not situation or situation not in situations:
|
165
161
|
cont()
|
166
162
|
else:
|
167
163
|
cookie = (_state.cookies or [None])[-1]
|
168
164
|
_state.task_queue.append((cont, cookie))
|
165
|
+
|
169
166
|
return inner
|
167
|
+
|
170
168
|
return wrapper
|
educommon/objectpack/actions.py
CHANGED
@@ -60,12 +60,11 @@ class BaseGridPack(BasePack):
|
|
60
60
|
|
61
61
|
@property
|
62
62
|
def id_param_name(self):
|
63
|
-
return '
|
63
|
+
return f'{self.short_name}_id'
|
64
64
|
|
65
65
|
@property
|
66
66
|
def grid_panel(cls):
|
67
|
-
"""
|
68
|
-
Класс панели с гридом.
|
67
|
+
"""Класс панели с гридом.
|
69
68
|
|
70
69
|
.. note::
|
71
70
|
Вынесено в метод для случая, когда пак работает с гридом,
|
@@ -74,14 +73,14 @@ class BaseGridPack(BasePack):
|
|
74
73
|
return cls.window.grid_panel_cls
|
75
74
|
|
76
75
|
def __init__(self):
|
77
|
-
super(
|
76
|
+
super().__init__()
|
77
|
+
|
78
78
|
self.grid_action = BaseGridCreateAction()
|
79
79
|
self.window_action = BaseGridWinAction()
|
80
80
|
self.actions.extend([self.grid_action, self.window_action])
|
81
81
|
|
82
82
|
def create_columns(self, request, context):
|
83
|
-
"""
|
84
|
-
Метод возвращающий колонки.
|
83
|
+
"""Метод возвращающий колонки.
|
85
84
|
|
86
85
|
.. seealso:: objectpack.actions.ObjectPack.columns
|
87
86
|
|
@@ -90,18 +89,17 @@ class BaseGridPack(BasePack):
|
|
90
89
|
return []
|
91
90
|
|
92
91
|
def create_grid(self, columns):
|
93
|
-
"""
|
94
|
-
Создание грида.
|
92
|
+
"""Создание грида.
|
95
93
|
|
96
94
|
:param list columns: список колонок
|
97
95
|
:rtype: m3_ext.ui.ExtObjectGrid
|
98
96
|
"""
|
99
97
|
grid = self.grid_panel.create_grid(pack=self, columns=columns)
|
98
|
+
|
100
99
|
return grid
|
101
100
|
|
102
101
|
def set_grid_params(self, grid, request, context):
|
103
|
-
"""
|
104
|
-
Настройка параметров для конфигурации грида.
|
102
|
+
"""Настройка параметров для конфигурации грида.
|
105
103
|
|
106
104
|
Параметры грида передаются панели с гридом в метод configure_grid.
|
107
105
|
:param grid: грид
|
@@ -115,11 +113,12 @@ class BaseGridPack(BasePack):
|
|
115
113
|
"""
|
116
114
|
# пак для настройки грида (column_param_name, id_param_name, url_data)
|
117
115
|
params = {'pack': self}
|
116
|
+
|
118
117
|
return params
|
119
118
|
|
120
119
|
def configure_grid(self, grid, request, context):
|
121
|
-
"""
|
122
|
-
|
120
|
+
"""Метод конфигурирования грида после его создания.
|
121
|
+
|
123
122
|
:param grid: грид
|
124
123
|
:type grid: m3_ext.ui.ExtObjectGrid
|
125
124
|
:param request: Запрос
|
@@ -129,34 +128,31 @@ class BaseGridPack(BasePack):
|
|
129
128
|
"""
|
130
129
|
params = self.set_grid_params(grid, request, context)
|
131
130
|
grid = self.grid_panel.configure_grid(grid, params)
|
131
|
+
|
132
132
|
return grid
|
133
133
|
|
134
134
|
def get_grid_action_url(self):
|
135
|
-
"""
|
136
|
-
Получение адреса экшна построения грид.
|
135
|
+
"""Получение адреса экшна построения грид.
|
137
136
|
|
138
137
|
:rtype: str
|
139
138
|
"""
|
140
139
|
return self.grid_action.get_absolute_url()
|
141
140
|
|
142
141
|
def get_rows_url(self):
|
143
|
-
"""
|
144
|
-
Получение адреса экшна, возвращающего строки грида.
|
142
|
+
"""Получение адреса экшна, возвращающего строки грида.
|
145
143
|
|
146
144
|
Должен быть определен в потомке.
|
147
145
|
:rtype: str
|
148
146
|
"""
|
149
|
-
raise NotImplementedError(
|
150
|
-
"Не определен метод get_rows_url() "
|
151
|
-
"в %s!" % self.__class__.__name__)
|
147
|
+
raise NotImplementedError(f'Не определен метод get_rows_url() в {self.__class__.__name__}!')
|
152
148
|
|
153
149
|
def create_window(self, request, context):
|
154
150
|
"""Получение окна."""
|
155
151
|
return self.window()
|
156
152
|
|
157
153
|
def get_window_params(self, request, context):
|
158
|
-
"""
|
159
|
-
|
154
|
+
"""Параметры для показа окна.
|
155
|
+
|
160
156
|
:param request: Запрос
|
161
157
|
:type request: django.http.HttpRequest
|
162
158
|
:param context: Контекст
|
@@ -170,8 +166,9 @@ class BaseGridPack(BasePack):
|
|
170
166
|
"""
|
171
167
|
params = {
|
172
168
|
# пак отвечающий за получения грида окном
|
173
|
-
|
169
|
+
'grid_pack': self
|
174
170
|
}
|
171
|
+
|
175
172
|
return params
|
176
173
|
|
177
174
|
|
@@ -185,6 +182,7 @@ class BaseGridCreateAction(BaseAction):
|
|
185
182
|
columns = pack.create_columns(request, context)
|
186
183
|
grid = pack.create_grid(columns)
|
187
184
|
pack.configure_grid(grid, request, context)
|
185
|
+
|
188
186
|
return ExtUIComponentResult(grid)
|
189
187
|
|
190
188
|
|
@@ -197,15 +195,14 @@ class BaseGridWinAction(BaseWindowAction):
|
|
197
195
|
self.win = self.parent.create_window(self.request, self.context)
|
198
196
|
|
199
197
|
def set_window_params(self):
|
200
|
-
super(
|
201
|
-
|
202
|
-
|
198
|
+
super().set_window_params()
|
199
|
+
|
200
|
+
self.win_params = self.parent.get_window_params(self.request, self.context)
|
203
201
|
|
204
202
|
|
205
203
|
class ExtObjectRowsAction(ObjectRowsAction):
|
206
204
|
def get_total_count(self):
|
207
|
-
"""
|
208
|
-
В отличие от оригинала убирает из запроса лишнюю обработку даных.
|
205
|
+
"""В отличие от оригинала убирает из запроса лишнюю обработку данных.
|
209
206
|
|
210
207
|
:return: Количество объектов в выборке
|
211
208
|
:rtype: int
|
@@ -214,10 +211,10 @@ class ExtObjectRowsAction(ObjectRowsAction):
|
|
214
211
|
|
215
212
|
|
216
213
|
class RelationsCheckMixin:
|
217
|
-
"""
|
218
|
-
|
219
|
-
ссылок на редактируемый/удаляемый объект
|
220
|
-
в табличном виде.
|
214
|
+
"""Миксин для экшенов удаления и редактирования.
|
215
|
+
|
216
|
+
Проверяет наличие ссылок на редактируемый/удаляемый объект
|
217
|
+
и выводящий данную информацию в табличном виде.
|
221
218
|
"""
|
222
219
|
|
223
220
|
# Описание настроек отображения информации для каждой модели.
|
@@ -229,8 +226,7 @@ class RelationsCheckMixin:
|
|
229
226
|
err_msg = 'На объект "{obj}" есть ссылки:'
|
230
227
|
render_template_name = 'relations-check-mixin-template.html'
|
231
228
|
|
232
|
-
def __init__(self, rel_conf=None, rel_list=None,
|
233
|
-
rel_ignore_list=None, err_msg=None, *args, **kwargs):
|
229
|
+
def __init__(self, rel_conf=None, rel_list=None, rel_ignore_list=None, err_msg=None, *args, **kwargs):
|
234
230
|
"""
|
235
231
|
:param rel_conf: настройки отображения
|
236
232
|
:type dict
|
@@ -265,28 +261,21 @@ class RelationsCheckMixin:
|
|
265
261
|
self.rel_ignore_list = rel_ignore_list
|
266
262
|
if err_msg:
|
267
263
|
self.err_msg = err_msg
|
268
|
-
|
264
|
+
|
265
|
+
super().__init__(*args, **kwargs)
|
269
266
|
|
270
267
|
def _get_relations_to_check(self):
|
271
268
|
"""Получение всех связанных моделей для проверки."""
|
272
269
|
model = self._get_check_model()
|
273
270
|
opts = ModelOptions(model)
|
274
|
-
all_related_objects = [
|
275
|
-
rel_obj.relation for rel_obj in opts.get_all_related_objects()
|
276
|
-
]
|
271
|
+
all_related_objects = [rel_obj.relation for rel_obj in opts.get_all_related_objects()]
|
277
272
|
result = all_related_objects[:]
|
278
273
|
|
279
274
|
if self.rel_ignore_list:
|
280
|
-
result = [
|
281
|
-
rel for rel in all_related_objects
|
282
|
-
if rel.field.model.__name__ not in self.rel_ignore_list
|
283
|
-
]
|
275
|
+
result = [rel for rel in all_related_objects if rel.field.model.__name__ not in self.rel_ignore_list]
|
284
276
|
|
285
277
|
if self.rel_list:
|
286
|
-
result = [
|
287
|
-
rel for rel in all_related_objects
|
288
|
-
if rel.field.model.__name__ in self.rel_list
|
289
|
-
]
|
278
|
+
result = [rel for rel in all_related_objects if rel.field.model.__name__ in self.rel_list]
|
290
279
|
|
291
280
|
return result
|
292
281
|
|
@@ -295,11 +284,10 @@ class RelationsCheckMixin:
|
|
295
284
|
|
296
285
|
def _extract_proxy_from_model(model):
|
297
286
|
"""Если получена не модель, а прокси, то извлекает из него модель.
|
287
|
+
|
298
288
|
Функция рекурсивна, т.к. возможны прокси на прокси.
|
299
289
|
"""
|
300
|
-
if issubclass(model, ModelProxy) and hasattr(
|
301
|
-
model, 'model'
|
302
|
-
):
|
290
|
+
if issubclass(model, ModelProxy) and hasattr(model, 'model'):
|
303
291
|
model = _extract_proxy_from_model(model.model)
|
304
292
|
elif model._meta.proxy:
|
305
293
|
# прокси django
|
@@ -314,11 +302,12 @@ class RelationsCheckMixin:
|
|
314
302
|
ids = getattr(context, self.parent.id_param_name, [])
|
315
303
|
if isinstance(ids, int):
|
316
304
|
ids = [ids]
|
305
|
+
|
317
306
|
return self._get_check_model().objects.filter(id__in=ids)
|
318
307
|
|
319
308
|
def collect_related_objects(self, request, context):
|
320
|
-
"""
|
321
|
-
|
309
|
+
"""Получение списка связанных объектов.
|
310
|
+
|
322
311
|
:param request: Запрос
|
323
312
|
:type request: django.http.HttpRequest
|
324
313
|
:param context: Контекст
|
@@ -336,26 +325,25 @@ class RelationsCheckMixin:
|
|
336
325
|
for obj in objects:
|
337
326
|
assert isinstance(obj, model)
|
338
327
|
|
339
|
-
object_relations = result.setdefault(
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
328
|
+
object_relations = result.setdefault(
|
329
|
+
obj.id,
|
330
|
+
{
|
331
|
+
'object': obj,
|
332
|
+
'relations': [],
|
333
|
+
'err_msg': self.err_msg.format(
|
334
|
+
model_verbose=model._meta.verbose_name.capitalize(),
|
335
|
+
obj=obj,
|
336
|
+
),
|
337
|
+
},
|
338
|
+
)
|
347
339
|
|
348
340
|
for rel in relations:
|
349
|
-
assert getattr(
|
350
|
-
rel, 'parent_model', getattr(rel, 'model')
|
351
|
-
) == model
|
341
|
+
assert getattr(rel, 'parent_model', getattr(rel, 'model')) == model
|
352
342
|
|
353
343
|
rel_model_name = rel.field.model.__name__
|
354
344
|
conf = self.rel_conf.get(rel_model_name, {})
|
355
345
|
|
356
|
-
query = rel.field.model.objects.filter(
|
357
|
-
**{str(rel.field.attname): obj.pk}
|
358
|
-
)
|
346
|
+
query = rel.field.model.objects.filter(**{str(rel.field.attname): obj.pk})
|
359
347
|
if conf.get('get_query'):
|
360
348
|
query = conf['get_query'](query, obj)
|
361
349
|
|
@@ -367,14 +355,15 @@ class RelationsCheckMixin:
|
|
367
355
|
objects = [display(o) for o in query]
|
368
356
|
|
369
357
|
if count:
|
370
|
-
object_relations['relations'].append(
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
358
|
+
object_relations['relations'].append(
|
359
|
+
{
|
360
|
+
'model': rel.field.model,
|
361
|
+
'title': (conf.get('title') or rel.field.model._meta.verbose_name),
|
362
|
+
'columns': conf.get('columns'),
|
363
|
+
'objects': objects,
|
364
|
+
'count': count,
|
365
|
+
}
|
366
|
+
)
|
378
367
|
|
379
368
|
return dict(
|
380
369
|
items=[v for v in result.values() if v['relations']],
|
@@ -382,8 +371,8 @@ class RelationsCheckMixin:
|
|
382
371
|
)
|
383
372
|
|
384
373
|
def pre_run(self, request, context):
|
385
|
-
"""
|
386
|
-
|
374
|
+
"""Вывод окна отчета.
|
375
|
+
|
387
376
|
:param request: Запрос
|
388
377
|
:type request: django.http.HttpRequest
|
389
378
|
:param context: Контекст
|
@@ -391,13 +380,11 @@ class RelationsCheckMixin:
|
|
391
380
|
|
392
381
|
"""
|
393
382
|
|
394
|
-
super(
|
383
|
+
super().pre_run(request, context)
|
395
384
|
|
396
|
-
related_objects_data = self.collect_related_objects(
|
397
|
-
request, context)
|
385
|
+
related_objects_data = self.collect_related_objects(request, context)
|
398
386
|
|
399
387
|
if related_objects_data['items']:
|
400
|
-
|
401
388
|
html = render_to_string(
|
402
389
|
self.render_template_name,
|
403
390
|
related_objects_data,
|
@@ -406,10 +393,7 @@ class RelationsCheckMixin:
|
|
406
393
|
win = ui.RelatedErrorWindow()
|
407
394
|
win.set_params(params)
|
408
395
|
|
409
|
-
return OperationResult(
|
410
|
-
success=False,
|
411
|
-
code=win.get_script()
|
412
|
-
)
|
396
|
+
return OperationResult(success=False, code=win.get_script())
|
413
397
|
|
414
398
|
|
415
399
|
class ViewWindowPackMixin:
|
@@ -419,16 +403,14 @@ class ViewWindowPackMixin:
|
|
419
403
|
"""
|
420
404
|
|
421
405
|
def create_edit_window(self, create_new, request, context):
|
422
|
-
window = super(
|
423
|
-
|
424
|
-
)
|
406
|
+
window = super().create_edit_window(create_new, request, context)
|
407
|
+
|
425
408
|
window.make_read_only()
|
409
|
+
|
426
410
|
return window
|
427
411
|
|
428
412
|
def create_list_window(self, is_select_mode, request, context):
|
429
|
-
window = super(
|
430
|
-
is_select_mode, request, context
|
431
|
-
)
|
413
|
+
window = super().create_list_window(is_select_mode, request, context)
|
432
414
|
|
433
415
|
reconfigure_grid_by_access(window.grid)
|
434
416
|
|
educommon/objectpack/apps.py
CHANGED
@@ -4,6 +4,11 @@ from django.apps import (
|
|
4
4
|
|
5
5
|
|
6
6
|
class EduObjectPackConfig(AppConfig):
|
7
|
+
"""Конфигурация приложения educommon.objectpack.
|
8
|
+
|
9
|
+
Определяет имя, метку и читаемое имя Django-приложения,
|
10
|
+
содержащего расширения и дополнения к objectpack.
|
11
|
+
"""
|
7
12
|
|
8
13
|
name = 'educommon.objectpack'
|
9
14
|
label = 'educommon_objectpack'
|