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.
Files changed (221) hide show
  1. educommon/__init__.py +0 -1
  2. educommon/about/ui/actions.py +16 -30
  3. educommon/about/ui/ui.py +3 -12
  4. educommon/about/utils.py +6 -5
  5. educommon/async_task/__init__.py +0 -1
  6. educommon/async_task/actions.py +18 -13
  7. educommon/async_task/apps.py +4 -0
  8. educommon/async_task/locker.py +2 -5
  9. educommon/async_task/migrations/0001_initial.py +55 -9
  10. educommon/async_task/migrations/0002_task_type_and_status_data.py +94 -89
  11. educommon/async_task/migrations/0003_alter_runningtask_options.py +0 -1
  12. educommon/async_task/models.py +9 -6
  13. educommon/async_task/tasks.py +11 -7
  14. educommon/async_task/ui.py +16 -35
  15. educommon/async_tasks/__init__.py +0 -1
  16. educommon/async_tasks/apps.py +4 -0
  17. educommon/async_tasks/locks.py +11 -21
  18. educommon/async_tasks/migrations/0001_initial.py +68 -8
  19. educommon/async_tasks/migrations/0002_load_initial_data.py +0 -1
  20. educommon/async_tasks/models.py +9 -29
  21. educommon/async_tasks/tasks.py +25 -54
  22. educommon/audit_log/__init__.py +1 -0
  23. educommon/audit_log/actions.py +27 -36
  24. educommon/audit_log/app_meta.py +7 -4
  25. educommon/audit_log/apps.py +44 -29
  26. educommon/audit_log/constants.py +7 -4
  27. educommon/audit_log/error_log/actions.py +1 -3
  28. educommon/audit_log/helpers.py +2 -4
  29. educommon/audit_log/management/commands/reinstall_audit_log.py +11 -7
  30. educommon/audit_log/migrations/0001_initial.py +91 -16
  31. educommon/audit_log/migrations/0002_install_audit_log.py +13 -13
  32. educommon/audit_log/migrations/0003_logproxy.py +1 -3
  33. educommon/audit_log/migrations/0004_reinstall_audit_log.py +1 -4
  34. educommon/audit_log/migrations/0005_postgresql_error.py +4 -2
  35. educommon/audit_log/migrations/0006_auto_20200806_1707.py +3 -4
  36. educommon/audit_log/migrations/0007_create_selective_tables_function.py +8 -5
  37. educommon/audit_log/migrations/0008_table_logged.py +0 -1
  38. educommon/audit_log/migrations/0009_reinstall_audit_log.py +0 -1
  39. educommon/audit_log/models.py +36 -42
  40. educommon/audit_log/permissions.py +11 -9
  41. educommon/audit_log/proxies.py +12 -23
  42. educommon/audit_log/ui.py +18 -15
  43. educommon/audit_log/utils/__init__.py +28 -60
  44. educommon/audit_log/utils/operations.py +16 -2
  45. educommon/auth/__init__.py +0 -3
  46. educommon/auth/rbac/__init__.py +2 -4
  47. educommon/auth/rbac/actions.py +148 -145
  48. educommon/auth/rbac/app_meta.py +9 -6
  49. educommon/auth/rbac/backends/base.py +2 -8
  50. educommon/auth/rbac/backends/caching.py +27 -37
  51. educommon/auth/rbac/backends/simple.py +1 -4
  52. educommon/auth/rbac/checker.py +1 -3
  53. educommon/auth/rbac/management/commands/rbac.py +6 -11
  54. educommon/auth/rbac/manager.py +18 -47
  55. educommon/auth/rbac/migrations/0001_initial.py +73 -12
  56. educommon/auth/rbac/migrations/0002_model_modifier_metaclass_fix.py +7 -6
  57. educommon/auth/rbac/migrations/0003_permission_hidden.py +1 -5
  58. educommon/auth/rbac/migrations/0004_auto_20171024_1245.py +26 -19
  59. educommon/auth/rbac/models.py +63 -68
  60. educommon/auth/rbac/permissions.py +6 -7
  61. educommon/auth/rbac/ui.py +83 -84
  62. educommon/auth/rbac/utils.py +10 -11
  63. educommon/auth/rbac/validators.py +4 -5
  64. educommon/auth/simple_auth/__init__.py +1 -5
  65. educommon/auth/simple_auth/actions.py +79 -92
  66. educommon/auth/simple_auth/app_meta.py +2 -9
  67. educommon/auth/simple_auth/checkers.py +3 -3
  68. educommon/auth/simple_auth/migrations/0001_initial.py +23 -4
  69. educommon/auth/simple_auth/validators.py +0 -1
  70. educommon/contingent/actions.py +7 -7
  71. educommon/contingent/app_meta.py +1 -4
  72. educommon/contingent/base.py +10 -15
  73. educommon/contingent/catalogs.py +424 -540
  74. educommon/contingent/contingent_plugin/actions.py +4 -15
  75. educommon/contingent/contingent_plugin/apps.py +10 -4
  76. educommon/contingent/contingent_plugin/migrations/0001_initial.py +5 -6
  77. educommon/contingent/contingent_plugin/migrations/0002_add_contingent_model_deleted.py +6 -11
  78. educommon/contingent/contingent_plugin/model_views.py +2 -12
  79. educommon/contingent/contingent_plugin/models.py +2 -7
  80. educommon/contingent/contingent_plugin/observer.py +14 -13
  81. educommon/contingent/contingent_plugin/plugin_meta.py +1 -3
  82. educommon/contingent/contingent_plugin/storage.py +8 -7
  83. educommon/contingent/contingent_plugin/utils.py +6 -6
  84. educommon/django/db/fields.py +72 -86
  85. educommon/django/db/migration/__init__.py +3 -7
  86. educommon/django/db/migration/operations.py +29 -51
  87. educommon/django/db/mixins/__init__.py +16 -10
  88. educommon/django/db/mixins/date_interval.py +47 -75
  89. educommon/django/db/mixins/validation.py +26 -26
  90. educommon/django/db/model_view/__init__.py +18 -22
  91. educommon/django/db/models.py +9 -8
  92. educommon/django/db/observer.py +9 -27
  93. educommon/django/db/partitioning/__init__.py +66 -92
  94. educommon/django/db/partitioning/management/commands/apply_partitioning.py +3 -13
  95. educommon/django/db/partitioning/management/commands/clear_table.py +18 -14
  96. educommon/django/db/partitioning/management/commands/split_table.py +18 -13
  97. educommon/django/db/routers.py +6 -15
  98. educommon/django/db/signals.py +149 -2
  99. educommon/django/db/utils.py +14 -19
  100. educommon/django/db/validators/__init__.py +1 -0
  101. educommon/django/db/validators/simple.py +72 -100
  102. educommon/django/storages/atcfs/api.py +39 -53
  103. educommon/django/storages/atcfs/app_meta.py +1 -1
  104. educommon/django/storages/atcfs/management/commands/atcfs_migrate.py +42 -55
  105. educommon/django/storages/atcfs/models.py +0 -3
  106. educommon/django/storages/atcfs/monkey_patching.py +18 -12
  107. educommon/django/storages/atcfs/storage.py +14 -23
  108. educommon/extjs/fields/input_params.py +15 -45
  109. educommon/importer/XLSReader.py +143 -241
  110. educommon/importer/__init__.py +86 -4
  111. educommon/importer/api.py +53 -84
  112. educommon/importer/constants.py +4 -14
  113. educommon/importer/loggers.py +16 -26
  114. educommon/importer/proxy.py +131 -176
  115. educommon/importer/proxy_import.py +11 -12
  116. educommon/importer/report.py +4 -6
  117. educommon/importer/ui.py +32 -26
  118. educommon/importer/validators.py +4 -7
  119. educommon/integration_entities/helpers.py +14 -18
  120. educommon/ioc/__init__.py +3 -6
  121. educommon/logger/loggers.py +10 -14
  122. educommon/m3/__init__.py +20 -38
  123. educommon/m3/extensions/__init__.py +1 -0
  124. educommon/m3/extensions/listeners/__init__.py +22 -38
  125. educommon/m3/extensions/listeners/delete_check/listeners.py +31 -41
  126. educommon/m3/extensions/listeners/delete_check/mixins.py +20 -25
  127. educommon/m3/extensions/listeners/delete_check/signals.py +2 -2
  128. educommon/m3/extensions/listeners/delete_check/ui.py +15 -14
  129. educommon/m3/extensions/listeners/delete_check/utils.py +9 -11
  130. educommon/m3/extensions/ui.py +15 -33
  131. educommon/m3/transaction_context.py +17 -19
  132. educommon/objectpack/actions.py +70 -88
  133. educommon/objectpack/apps.py +5 -0
  134. educommon/objectpack/filters.py +9 -15
  135. educommon/objectpack/ui.py +59 -77
  136. educommon/report/__init__.py +9 -5
  137. educommon/report/actions.py +29 -32
  138. educommon/report/constructor/__init__.py +5 -8
  139. educommon/report/constructor/app_meta.py +1 -3
  140. educommon/report/constructor/apps.py +1 -0
  141. educommon/report/constructor/base.py +33 -80
  142. educommon/report/constructor/builders/excel/_base.py +138 -286
  143. educommon/report/constructor/builders/excel/_header.py +2 -9
  144. educommon/report/constructor/builders/excel/product.py +13 -34
  145. educommon/report/constructor/builders/excel/with_merged_cells.py +18 -14
  146. educommon/report/constructor/config.py +2 -0
  147. educommon/report/constructor/editor/actions.py +101 -215
  148. educommon/report/constructor/editor/ui.py +71 -93
  149. educommon/report/constructor/exceptions.py +6 -12
  150. educommon/report/constructor/migrations/0001_initial.py +36 -44
  151. educommon/report/constructor/migrations/0002_report_filters.py +86 -72
  152. educommon/report/constructor/migrations/0003_reportfilter_exclude.py +5 -5
  153. educommon/report/constructor/migrations/0004_reportfilter_fields.py +22 -18
  154. educommon/report/constructor/migrations/0005_reportcolumn_visible.py +5 -4
  155. educommon/report/constructor/migrations/0006_reportsorting.py +21 -17
  156. educommon/report/constructor/migrations/0007_include_available_units.py +14 -14
  157. educommon/report/constructor/migrations/0008_auto_20170407_1318.py +4 -5
  158. educommon/report/constructor/migrations/0009_auto_20180405_0642.py +1 -4
  159. educommon/report/constructor/migrations/0010_add_aggregate_fields.py +7 -8
  160. educommon/report/constructor/mixins.py +14 -15
  161. educommon/report/constructor/models.py +76 -124
  162. educommon/report/constructor/utils.py +3 -8
  163. educommon/report/constructor/validators.py +1 -3
  164. educommon/report/reporter.py +25 -43
  165. educommon/report/utils.py +14 -40
  166. educommon/rest/actions.py +7 -11
  167. educommon/rest/context.py +6 -16
  168. educommon/rest/controllers.py +10 -10
  169. educommon/rest/mixins.py +29 -27
  170. educommon/secure_media/app_meta.py +9 -9
  171. educommon/utils/__init__.py +3 -2
  172. educommon/utils/caching.py +1 -3
  173. educommon/utils/conversion.py +1 -3
  174. educommon/utils/crypto.py +1 -2
  175. educommon/utils/date.py +13 -26
  176. educommon/utils/db/__init__.py +17 -26
  177. educommon/utils/db/postgresql.py +1 -4
  178. educommon/utils/fonts/__init__.py +3 -4
  179. educommon/utils/licence/__init__.py +5 -16
  180. educommon/utils/misc.py +9 -18
  181. educommon/utils/object_grid.py +55 -62
  182. educommon/utils/phone_number/modelfields.py +1 -3
  183. educommon/utils/phone_number/phone_number.py +5 -8
  184. educommon/utils/phone_number/validators.py +8 -23
  185. educommon/utils/plugins.py +15 -28
  186. educommon/utils/registry.py +2 -1
  187. educommon/utils/seqtools.py +1 -3
  188. educommon/utils/serializer.py +9 -16
  189. educommon/utils/storage.py +3 -2
  190. educommon/utils/system.py +1 -3
  191. educommon/utils/system_app/management/commands/delete_objects.py +17 -34
  192. educommon/utils/ui.py +87 -84
  193. educommon/utils/xml/__init__.py +2 -7
  194. educommon/utils/xml/resolver.py +1 -0
  195. educommon/ws_log/actions.py +31 -76
  196. educommon/ws_log/base.py +6 -20
  197. educommon/ws_log/migrations/0001_initial.py +25 -8
  198. educommon/ws_log/migrations/0002_auto_20160628_1334.py +0 -1
  199. educommon/ws_log/migrations/0003_add_fields_to_smev_logs.py +20 -4
  200. educommon/ws_log/migrations/0004_auto_20160727_1600.py +7 -6
  201. educommon/ws_log/migrations/0005_auto_20161130_1615.py +14 -4
  202. educommon/ws_log/migrations/0006_auto_20170327_1027.py +3 -2
  203. educommon/ws_log/migrations/0007_auto_20180607_1040.py +8 -9
  204. educommon/ws_log/migrations/0008_auto_20180713_1445.py +23 -10
  205. educommon/ws_log/migrations/0009_auto_20201130_1553.py +7 -2
  206. educommon/ws_log/models.py +21 -35
  207. educommon/ws_log/provider.py +2 -1
  208. educommon/ws_log/report.py +8 -13
  209. educommon/ws_log/smev/applications.py +12 -27
  210. educommon/ws_log/smev/exceptions.py +2 -3
  211. educommon/ws_log/ui.py +32 -32
  212. educommon/ws_log/utils.py +1 -3
  213. educommon-3.13.2.dist-info/METADATA +57 -0
  214. educommon-3.13.2.dist-info/RECORD +354 -0
  215. {educommon-3.12.0.dist-info → educommon-3.13.2.dist-info}/WHEEL +1 -1
  216. educommon/utils/patches.py +0 -27
  217. educommon/version.conf +0 -11
  218. educommon-3.12.0.dist-info/METADATA +0 -47
  219. educommon-3.12.0.dist-info/RECORD +0 -357
  220. educommon-3.12.0.dist-info/dependency_links.txt +0 -1
  221. {educommon-3.12.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
- # Копипаста метода из Django 1.4 с добавлением вызова full_clean().
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
- # Копипаста метода из Django 1.4 с добавлением вызова full_clean().
66
- # Обусловлено невозможностью расширения метода.
67
- assert kwargs, (
68
- 'get_or_create() must be passed at least one keyword argument'
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(ModelValidationMixin, self).__init__(*args, **kwargs)
186
+ super().__init__(*args, **kwargs)
186
187
 
187
- assert not self.validators or all(
188
- isinstance(validator, IModelValidator)
189
- for validator in self.validators
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(ModelValidationMixin, self).clean()
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, ReverseOneToOneDescriptor,
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 = 'Указанный объект %s не существует.' % model_name
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(ModelValidationMixin, self).full_clean(exclude)
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(ModelValidationMixin, self).save(*args, **kwargs)
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
- dict(field.flatchoices).get(value, value),
160
- strings_only=True
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(HtmlTableView, self).__init__(model, *args, **kwargs)
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
- .format(key)
348
- )
342
+ raise ValueError('Для модели {} не зарегистрировано представление.'.format(key))
343
+
344
+
349
345
  # -----------------------------------------------------------------------------
350
346
 
351
347
 
@@ -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(ReadOnlyMixin, self).safe_delete(*args, **kwargs)
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(ReadOnlyMixin, self).delete(*args, **kwargs)
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(ReadOnlyMixin, self).save(*args, **kwargs)
72
+ super().save(*args, **kwargs)
72
73
 
73
74
  class Meta:
74
75
  abstract = True
@@ -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(OriginalObjectMixin, self)._create_context(
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(OriginalObjectMixin, self)._create_context(instance)
225
+ result = super()._create_context(instance)
244
226
 
245
227
  if instance.pk is None:
246
228
  result.original = None