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
@@ -47,8 +47,11 @@ class QuerySet(DjangoQuerySet):
|
|
47
47
|
"""
|
48
48
|
|
49
49
|
def create(self, **kwargs):
|
50
|
-
|
51
|
-
|
50
|
+
"""Создаёт объект модели.
|
51
|
+
|
52
|
+
Копипаста метода из Django 1.4 с добавлением вызова full_clean().
|
53
|
+
Обусловлено невозможностью расширения метода.
|
54
|
+
"""
|
52
55
|
if self.model.clean_and_save_inside_transaction:
|
53
56
|
cm = atomic()
|
54
57
|
else:
|
@@ -59,14 +62,16 @@ class QuerySet(DjangoQuerySet):
|
|
59
62
|
obj.full_clean()
|
60
63
|
self._for_write = True
|
61
64
|
obj.save(force_insert=True, using=self.db)
|
65
|
+
|
62
66
|
return obj
|
63
67
|
|
64
68
|
def get_or_create(self, **kwargs):
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
69
|
+
"""Ищет или создаёт объект модели.
|
70
|
+
|
71
|
+
Копипаста метода из Django 1.4 с добавлением вызова full_clean().
|
72
|
+
Обусловлено невозможностью расширения метода.
|
73
|
+
"""
|
74
|
+
assert kwargs, 'get_or_create() must be passed at least one keyword argument'
|
70
75
|
defaults = kwargs.pop('defaults', {})
|
71
76
|
lookup = kwargs.copy()
|
72
77
|
for f in getattr(self.model, '_meta').fields:
|
@@ -77,9 +82,7 @@ class QuerySet(DjangoQuerySet):
|
|
77
82
|
return self.get(**lookup), False
|
78
83
|
except self.model.DoesNotExist:
|
79
84
|
try:
|
80
|
-
params = dict(
|
81
|
-
[(k, v) for k, v in kwargs.items() if '__' not in k]
|
82
|
-
)
|
85
|
+
params = dict([(k, v) for k, v in kwargs.items() if '__' not in k])
|
83
86
|
params.update(defaults)
|
84
87
|
obj = self.model(**params)
|
85
88
|
obj.full_clean()
|
@@ -146,7 +149,6 @@ class ModelValidationMixin(models.Model):
|
|
146
149
|
|
147
150
|
# models.py основной системы
|
148
151
|
class MyModel(BaseModel):
|
149
|
-
|
150
152
|
# Поле обязательно в основной системе
|
151
153
|
read_rules = models.BooleanField(...)
|
152
154
|
|
@@ -157,12 +159,11 @@ class ModelValidationMixin(models.Model):
|
|
157
159
|
RequiredBooleanValidator('read_rules'),
|
158
160
|
]
|
159
161
|
|
162
|
+
|
160
163
|
# extenders.py в плагине
|
161
164
|
from app.models import MyModel
|
162
165
|
|
163
|
-
MyModel.validators.append(
|
164
|
-
RequiredBooleanValidator('read_rules_plugin')
|
165
|
-
)
|
166
|
+
MyModel.validators.append(RequiredBooleanValidator('read_rules_plugin'))
|
166
167
|
"""
|
167
168
|
|
168
169
|
#: Признак использования транзакций при проверке и сохранении.
|
@@ -182,12 +183,11 @@ class ModelValidationMixin(models.Model):
|
|
182
183
|
validators = []
|
183
184
|
|
184
185
|
def __init__(self, *args, **kwargs):
|
185
|
-
super(
|
186
|
+
super().__init__(*args, **kwargs)
|
186
187
|
|
187
|
-
assert not self.validators or all(
|
188
|
-
|
189
|
-
|
190
|
-
), self.validators
|
188
|
+
assert not self.validators or all(isinstance(validator, IModelValidator) for validator in self.validators), (
|
189
|
+
self.validators
|
190
|
+
)
|
191
191
|
|
192
192
|
self.__set_valid_flag(False)
|
193
193
|
|
@@ -205,7 +205,7 @@ class ModelValidationMixin(models.Model):
|
|
205
205
|
errors = defaultdict(list)
|
206
206
|
|
207
207
|
try:
|
208
|
-
super(
|
208
|
+
super().clean()
|
209
209
|
except ValidationError as error:
|
210
210
|
errors.update(error.update_error_dict(errors))
|
211
211
|
|
@@ -218,7 +218,8 @@ class ModelValidationMixin(models.Model):
|
|
218
218
|
# Фрейм, в котором сгенерировано исключение, будет последним.
|
219
219
|
error_frame = inspect.getinnerframes(tb)[-1][0]
|
220
220
|
descriptior_types = (
|
221
|
-
ForwardOneToOneDescriptor,
|
221
|
+
ForwardOneToOneDescriptor,
|
222
|
+
ReverseOneToOneDescriptor,
|
222
223
|
)
|
223
224
|
# Источником исключения может быть модель, кварисет или дескриптор
|
224
225
|
exception_source = error_frame.f_locals['self']
|
@@ -240,7 +241,7 @@ class ModelValidationMixin(models.Model):
|
|
240
241
|
model_name = model_or_query._meta.verbose_name
|
241
242
|
elif isinstance(model_or_query, models.QuerySet):
|
242
243
|
model_name = model_or_query.model._meta.verbose_name
|
243
|
-
message = 'Указанный объект
|
244
|
+
message = f'Указанный объект {model_name} не существует.'
|
244
245
|
|
245
246
|
errors.update({NON_FIELD_ERRORS: message})
|
246
247
|
|
@@ -271,7 +272,7 @@ class ModelValidationMixin(models.Model):
|
|
271
272
|
pre_clean.send(sender=self.__class__, instance=self, errors=errors)
|
272
273
|
|
273
274
|
try:
|
274
|
-
super(
|
275
|
+
super().full_clean(exclude)
|
275
276
|
except ValidationError as error:
|
276
277
|
errors.update(error.update_error_dict(errors))
|
277
278
|
|
@@ -287,13 +288,12 @@ class ModelValidationMixin(models.Model):
|
|
287
288
|
"""После сохранения объекта снимает отметку о выполнении валидации."""
|
288
289
|
if not self.ready_to_save:
|
289
290
|
raise AssertionError(
|
290
|
-
'Attempt to save data without validation '
|
291
|
-
'(model {}.{})'.format(
|
291
|
+
'Attempt to save data without validation (model {}.{})'.format(
|
292
292
|
self.__class__.__module__, self.__class__.__name__
|
293
293
|
)
|
294
294
|
)
|
295
295
|
|
296
|
-
super(
|
296
|
+
super().save(*args, **kwargs)
|
297
297
|
|
298
298
|
# Перед следующим сохранением нужно будет снова вызвать full_clean
|
299
299
|
self.__set_valid_flag(False)
|
@@ -4,6 +4,7 @@
|
|
4
4
|
является формирование какого-либо представления (HTML, JSON и т.п.) на основе
|
5
5
|
объекта модели.
|
6
6
|
"""
|
7
|
+
|
7
8
|
from abc import (
|
8
9
|
ABCMeta,
|
9
10
|
abstractmethod,
|
@@ -64,6 +65,8 @@ class ModelView(metaclass=ABCMeta):
|
|
64
65
|
@abstractmethod
|
65
66
|
def get_view(self, objects):
|
66
67
|
"""Возвращает представление для указанных объектов."""
|
68
|
+
|
69
|
+
|
67
70
|
# -----------------------------------------------------------------------------
|
68
71
|
# Извлечение данных из объектов
|
69
72
|
|
@@ -77,7 +80,6 @@ class DataExtractor(metaclass=ABCMeta):
|
|
77
80
|
|
78
81
|
|
79
82
|
class Text(DataExtractor):
|
80
|
-
|
81
83
|
def __init__(self, text):
|
82
84
|
self._text = text
|
83
85
|
|
@@ -155,10 +157,9 @@ class FieldChoiceValue(DataExtractor):
|
|
155
157
|
except AttributeError:
|
156
158
|
return ''
|
157
159
|
else:
|
158
|
-
return force_str(
|
159
|
-
|
160
|
-
|
161
|
-
)
|
160
|
+
return force_str(dict(field.flatchoices).get(value, value), strings_only=True)
|
161
|
+
|
162
|
+
|
162
163
|
# -----------------------------------------------------------------------------
|
163
164
|
|
164
165
|
|
@@ -174,13 +175,14 @@ class HtmlTableView(ModelView):
|
|
174
175
|
class SubjectOffice(models.Model):
|
175
176
|
subject = models.ForeignKey(
|
176
177
|
'subject.Subject',
|
177
|
-
verbose_name=
|
178
|
+
verbose_name='Предмет',
|
178
179
|
)
|
179
180
|
office = models.ForeignKey(
|
180
181
|
'office.Office',
|
181
|
-
verbose_name=
|
182
|
+
verbose_name='Аудитория',
|
182
183
|
)
|
183
184
|
|
185
|
+
|
184
186
|
subject_office_view = HtmlTableView(
|
185
187
|
model='subject.SubjectOffice',
|
186
188
|
columns=(
|
@@ -213,7 +215,7 @@ class HtmlTableView(ModelView):
|
|
213
215
|
_columns = ()
|
214
216
|
|
215
217
|
def __init__(self, model, columns, *args, **kwargs):
|
216
|
-
super(
|
218
|
+
super().__init__(model, *args, **kwargs)
|
217
219
|
|
218
220
|
self._columns = columns
|
219
221
|
|
@@ -229,20 +231,14 @@ class HtmlTableView(ModelView):
|
|
229
231
|
if all(not column.get('header') for column in self._columns):
|
230
232
|
return None
|
231
233
|
|
232
|
-
return tuple(
|
233
|
-
column['header'].get(model)
|
234
|
-
for column in self._columns
|
235
|
-
)
|
234
|
+
return tuple(column['header'].get(model) for column in self._columns)
|
236
235
|
|
237
236
|
def _get_body_data(self, objects):
|
238
237
|
"""Возвращает данные для ячеек тела таблицы.
|
239
238
|
|
240
239
|
:rtype: tuple
|
241
240
|
"""
|
242
|
-
return tuple(
|
243
|
-
tuple(column['data'].get(obj) for column in self._columns)
|
244
|
-
for obj in objects
|
245
|
-
)
|
241
|
+
return tuple(tuple(column['data'].get(obj) for column in self._columns) for obj in objects)
|
246
242
|
|
247
243
|
def get_view(self, objects):
|
248
244
|
"""Возвращает строку с HTML-таблицей, содержащей данные объектов.
|
@@ -271,6 +267,8 @@ class HtmlTableView(ModelView):
|
|
271
267
|
body=self._get_body_data(objects),
|
272
268
|
),
|
273
269
|
)
|
270
|
+
|
271
|
+
|
274
272
|
# -----------------------------------------------------------------------------
|
275
273
|
|
276
274
|
|
@@ -315,8 +313,7 @@ class ModelViewRegistry:
|
|
315
313
|
# Сравниваем приоритеты представлений
|
316
314
|
if registered_view.priority == view.priority:
|
317
315
|
raise ValueError(
|
318
|
-
'Для модели {} уже зарегистрировано '
|
319
|
-
'представление {} с приоритетом {}.'.format(
|
316
|
+
'Для модели {} уже зарегистрировано представление {} с приоритетом {}.'.format(
|
320
317
|
key, view, view.priority
|
321
318
|
)
|
322
319
|
)
|
@@ -342,10 +339,9 @@ class ModelViewRegistry:
|
|
342
339
|
elif self._default_view:
|
343
340
|
return self._default_view
|
344
341
|
else:
|
345
|
-
raise ValueError(
|
346
|
-
|
347
|
-
|
348
|
-
)
|
342
|
+
raise ValueError('Для модели {} не зарегистрировано представление.'.format(key))
|
343
|
+
|
344
|
+
|
349
345
|
# -----------------------------------------------------------------------------
|
350
346
|
|
351
347
|
|
educommon/django/db/models.py
CHANGED
@@ -27,7 +27,6 @@ class BaseModel(
|
|
27
27
|
ReprStrPreModelMixin,
|
28
28
|
BaseObjectModel,
|
29
29
|
):
|
30
|
-
|
31
30
|
"""Базовый класс для всех моделей системы."""
|
32
31
|
|
33
32
|
class Meta:
|
@@ -35,7 +34,6 @@ class BaseModel(
|
|
35
34
|
|
36
35
|
|
37
36
|
class ReadOnlyMixin(models.Model):
|
38
|
-
|
39
37
|
"""Класс-примесь для моделей с записями только для чтения.
|
40
38
|
|
41
39
|
В основной модели должны быть реализованы два метода:
|
@@ -49,26 +47,29 @@ class ReadOnlyMixin(models.Model):
|
|
49
47
|
об ошибке. Параметр delete определяет операцию (False - изменение, True -
|
50
48
|
удаление).
|
51
49
|
"""
|
50
|
+
|
52
51
|
def _check_read_only(self, delete):
|
52
|
+
"""Вызывает исключение, если объект защищён от изменений или удаления."""
|
53
53
|
if self.is_read_only():
|
54
|
-
raise ApplicationLogicException(
|
55
|
-
self.get_read_only_error_message(delete=delete)
|
56
|
-
)
|
54
|
+
raise ApplicationLogicException(self.get_read_only_error_message(delete=delete))
|
57
55
|
|
58
56
|
def safe_delete(self, *args, **kwargs):
|
57
|
+
"""Удаляет объект, если он не помечен как только для чтения."""
|
59
58
|
self._check_read_only(delete=True)
|
60
59
|
|
61
|
-
return super(
|
60
|
+
return super().safe_delete(*args, **kwargs)
|
62
61
|
|
63
62
|
def delete(self, *args, **kwargs):
|
63
|
+
"""Удаляет объект, если он не помечен как только для чтения."""
|
64
64
|
self._check_read_only(delete=True)
|
65
65
|
|
66
|
-
super(
|
66
|
+
super().delete(*args, **kwargs)
|
67
67
|
|
68
68
|
def save(self, *args, **kwargs):
|
69
|
+
"""Сохраняет объект, если он не помечен как только для чтения."""
|
69
70
|
self._check_read_only(delete=False)
|
70
71
|
|
71
|
-
super(
|
72
|
+
super().save(*args, **kwargs)
|
72
73
|
|
73
74
|
class Meta:
|
74
75
|
abstract = True
|
educommon/django/db/observer.py
CHANGED
@@ -43,7 +43,7 @@ class ModelObserverBase(metaclass=SingletonMeta):
|
|
43
43
|
return model in self._observables
|
44
44
|
|
45
45
|
def _create_context(self, instance):
|
46
|
-
result = super(
|
46
|
+
result = super()._create_context(
|
47
47
|
instance
|
48
48
|
)
|
49
49
|
|
@@ -89,7 +89,6 @@ class ModelObserverBase(metaclass=SingletonMeta):
|
|
89
89
|
уничтожение сборщиком мусора.
|
90
90
|
"""
|
91
91
|
|
92
|
-
|
93
92
|
def _create_context(self, instance):
|
94
93
|
"""Возвращает контекст для экземпляра модели.
|
95
94
|
|
@@ -99,6 +98,7 @@ class ModelObserverBase(metaclass=SingletonMeta):
|
|
99
98
|
"""
|
100
99
|
context = self.Context()
|
101
100
|
self._contexts[context] = instance
|
101
|
+
|
102
102
|
return context
|
103
103
|
|
104
104
|
def _get_context(self, instance):
|
@@ -135,6 +135,7 @@ class ModelObserverBase(metaclass=SingletonMeta):
|
|
135
135
|
def inner(instance, sender, **kwargs):
|
136
136
|
if handler.__self__._is_observable(sender):
|
137
137
|
handler(instance=instance, sender=sender, **kwargs)
|
138
|
+
|
138
139
|
return inner
|
139
140
|
|
140
141
|
pre_save.connect(wrapper(self.__pre_save_handler), weak=False)
|
@@ -170,19 +171,11 @@ class ModelObserverBase(metaclass=SingletonMeta):
|
|
170
171
|
context = self._get_context(instance)
|
171
172
|
|
172
173
|
if hasattr(self, 'pre_save'):
|
173
|
-
self.pre_save(
|
174
|
-
instance=instance,
|
175
|
-
context=context,
|
176
|
-
**kwargs
|
177
|
-
)
|
174
|
+
self.pre_save(instance=instance, context=context, **kwargs)
|
178
175
|
|
179
176
|
def __post_save_handler(self, instance, **kwargs):
|
180
177
|
if hasattr(self, 'post_save'):
|
181
|
-
self.post_save(
|
182
|
-
instance=instance,
|
183
|
-
context=self._get_context(instance),
|
184
|
-
**kwargs
|
185
|
-
)
|
178
|
+
self.post_save(instance=instance, context=self._get_context(instance), **kwargs)
|
186
179
|
|
187
180
|
self._remove_context(instance)
|
188
181
|
|
@@ -193,19 +186,11 @@ class ModelObserverBase(metaclass=SingletonMeta):
|
|
193
186
|
context = self._get_context(instance)
|
194
187
|
|
195
188
|
if hasattr(self, 'pre_delete'):
|
196
|
-
self.pre_delete(
|
197
|
-
instance=instance,
|
198
|
-
context=context,
|
199
|
-
**kwargs
|
200
|
-
)
|
189
|
+
self.pre_delete(instance=instance, context=context, **kwargs)
|
201
190
|
|
202
191
|
def __post_delete_handler(self, instance, **kwargs):
|
203
192
|
if hasattr(self, 'post_delete'):
|
204
|
-
self.post_delete(
|
205
|
-
instance=instance,
|
206
|
-
context=self._get_context(instance),
|
207
|
-
**kwargs
|
208
|
-
)
|
193
|
+
self.post_delete(instance=instance, context=self._get_context(instance), **kwargs)
|
209
194
|
|
210
195
|
self._remove_context(instance)
|
211
196
|
|
@@ -221,10 +206,7 @@ class ModelDescendantsObserverMixin:
|
|
221
206
|
"""Класс примесь для наблюдения за моделями и их потомками."""
|
222
207
|
|
223
208
|
def _is_observable(self, model):
|
224
|
-
return any(
|
225
|
-
model is observable or issubclass(model, observable)
|
226
|
-
for observable in self._observables
|
227
|
-
)
|
209
|
+
return any(model is observable or issubclass(model, observable) for observable in self._observables)
|
228
210
|
|
229
211
|
|
230
212
|
class OriginalObjectMixin:
|
@@ -240,7 +222,7 @@ class OriginalObjectMixin:
|
|
240
222
|
__empty = _Empty()
|
241
223
|
|
242
224
|
def _create_context(self, instance):
|
243
|
-
result = super(
|
225
|
+
result = super()._create_context(instance)
|
244
226
|
|
245
227
|
if instance.pk is None:
|
246
228
|
result.original = None
|