educommon 3.5.5__py3-none-any.whl → 3.6.1__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/audit_log/helpers.py +1 -1
- educommon/auth/__init__.py +3 -1
- educommon/integration_entities/helpers.py +22 -0
- educommon/objectpack/actions.py +12 -0
- educommon/objectpack/filters.py +155 -0
- educommon/utils/object_grid.py +258 -0
- educommon/utils/ui.py +38 -0
- educommon/version.conf +5 -5
- {educommon-3.5.5.dist-info → educommon-3.6.1.dist-info}/METADATA +2 -2
- {educommon-3.5.5.dist-info → educommon-3.6.1.dist-info}/RECORD +13 -11
- {educommon-3.5.5.dist-info → educommon-3.6.1.dist-info}/WHEEL +0 -0
- {educommon-3.5.5.dist-info → educommon-3.6.1.dist-info}/dependency_links.txt +0 -0
- {educommon-3.5.5.dist-info → educommon-3.6.1.dist-info}/top_level.txt +0 -0
educommon/audit_log/helpers.py
CHANGED
educommon/auth/__init__.py
CHANGED
@@ -19,6 +19,10 @@ from django.utils import (
|
|
19
19
|
timezone,
|
20
20
|
)
|
21
21
|
|
22
|
+
from m3_db_utils.models import (
|
23
|
+
FictiveForeignKeyMixin,
|
24
|
+
)
|
25
|
+
|
22
26
|
from educommon.integration_entities.enums import (
|
23
27
|
EntityLogOperation,
|
24
28
|
)
|
@@ -75,8 +79,24 @@ class AbstractEntitySaver(ABC):
|
|
75
79
|
"""
|
76
80
|
return []
|
77
81
|
|
82
|
+
def _convert_fictive_foreign_keys(self, entities: Iterable[Model]):
|
83
|
+
"""Преобразование значений полей фиктивных внешних ключей.
|
84
|
+
|
85
|
+
В рамках метода производится проверка наличия фиктивного внешнего ключа у модели. Если они есть и заполнены
|
86
|
+
объектами модели, то производится получения идентификатора объекта модели и замена им самого объекта.
|
87
|
+
"""
|
88
|
+
for entity in entities:
|
89
|
+
if isinstance(entity, FictiveForeignKeyMixin):
|
90
|
+
for field_name in entity.fictive_foreign_key_field_names:
|
91
|
+
field_value = getattr(entity, field_name, None)
|
92
|
+
|
93
|
+
if field_value and isinstance(field_value, Model):
|
94
|
+
setattr(entity, field_name, getattr(field_value, 'pk'))
|
95
|
+
|
78
96
|
def _create_entities(self) -> None:
|
79
97
|
"""Создает новые записи."""
|
98
|
+
self._convert_fictive_foreign_keys(entities=self._to_create_entities)
|
99
|
+
|
80
100
|
self.model.objects.bulk_create(
|
81
101
|
self._to_create_entities,
|
82
102
|
batch_size=self.create_batch_size,
|
@@ -85,6 +105,8 @@ class AbstractEntitySaver(ABC):
|
|
85
105
|
|
86
106
|
def _update_entities(self) -> None:
|
87
107
|
"""Обновляет записи."""
|
108
|
+
self._convert_fictive_foreign_keys(entities=self._to_create_entities)
|
109
|
+
|
88
110
|
for entity in self._to_update_entities:
|
89
111
|
# Поле modified имеет свойство auto_now=True и оно не обновляется при update и bulk_update.
|
90
112
|
# Поэтому, его нужно обновить вручную:
|
educommon/objectpack/actions.py
CHANGED
@@ -19,6 +19,7 @@ from objectpack.actions import (
|
|
19
19
|
BaseAction,
|
20
20
|
BasePack,
|
21
21
|
BaseWindowAction,
|
22
|
+
ObjectRowsAction,
|
22
23
|
)
|
23
24
|
from objectpack.models import (
|
24
25
|
ModelProxy,
|
@@ -201,6 +202,17 @@ class BaseGridWinAction(BaseWindowAction):
|
|
201
202
|
self.request, self.context)
|
202
203
|
|
203
204
|
|
205
|
+
class ExtObjectRowsAction(ObjectRowsAction):
|
206
|
+
def get_total_count(self):
|
207
|
+
"""
|
208
|
+
В отличие от оригинала убирает из запроса лишнюю обработку даных.
|
209
|
+
|
210
|
+
:return: Количество объектов в выборке
|
211
|
+
:rtype: int
|
212
|
+
"""
|
213
|
+
return self.query.select_related(None).values('id').count()
|
214
|
+
|
215
|
+
|
204
216
|
class RelationsCheckMixin:
|
205
217
|
"""
|
206
218
|
Миксин для экшенов удаления и редактирования, проверяющий наличие
|
@@ -0,0 +1,155 @@
|
|
1
|
+
"""Дополнение колоночных фильтров."""
|
2
|
+
|
3
|
+
from django.db.models.expressions import (
|
4
|
+
Q,
|
5
|
+
)
|
6
|
+
from m3.actions import (
|
7
|
+
DeclarativeActionContext,
|
8
|
+
)
|
9
|
+
from m3.plugins import (
|
10
|
+
ExtensionManager,
|
11
|
+
)
|
12
|
+
from m3_ext.ui import (
|
13
|
+
all_components as ext,
|
14
|
+
)
|
15
|
+
|
16
|
+
from objectpack.filters import (
|
17
|
+
ColumnFilterEngine as BaseFilterEngine,
|
18
|
+
CustomFilter,
|
19
|
+
)
|
20
|
+
from objectpack.ui import (
|
21
|
+
_create_control_for_field,
|
22
|
+
make_combo_box,
|
23
|
+
)
|
24
|
+
|
25
|
+
from educommon.utils.ui import (
|
26
|
+
ColumnFilterWithDefaultValue,
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
class ColumnFilterEngine(BaseFilterEngine):
|
31
|
+
"""Колоночные фильтры с возможностью расширения плагином."""
|
32
|
+
|
33
|
+
def configure_grid(self, grid):
|
34
|
+
"""Метод конфигурации грида."""
|
35
|
+
# расширение плагином
|
36
|
+
if not ExtensionManager().execute(
|
37
|
+
'column_filter_engine.configure_grid', self, grid
|
38
|
+
):
|
39
|
+
super().configure_grid(grid)
|
40
|
+
|
41
|
+
|
42
|
+
class ModifiedChoicesFilter(CustomFilter):
|
43
|
+
"""Колоночный фильтр с выпадающим списком."""
|
44
|
+
|
45
|
+
def __init__(self, choices, *args, **kwargs):
|
46
|
+
"""Метод инициализации.
|
47
|
+
|
48
|
+
Добавляем значения для выбора и тип компонента.
|
49
|
+
"""
|
50
|
+
self._choices = choices
|
51
|
+
kwargs['xtype'] = 'combo'
|
52
|
+
|
53
|
+
super(ModifiedChoicesFilter, self).__init__(*args, **kwargs)
|
54
|
+
|
55
|
+
def create_control(self):
|
56
|
+
"""Контрол."""
|
57
|
+
if callable(self._choices):
|
58
|
+
choices = self._choices()
|
59
|
+
else:
|
60
|
+
choices = self._choices
|
61
|
+
return make_combo_box(data=list(choices))
|
62
|
+
|
63
|
+
def get_control(self):
|
64
|
+
"""Настройка контрола."""
|
65
|
+
control = self.create_control()
|
66
|
+
control._put_config_value('filterName', self._uid)
|
67
|
+
control._put_config_value('tooltip', self._tooltip or control.label)
|
68
|
+
control.name = self._uid
|
69
|
+
control.allow_blank = True
|
70
|
+
control.hide_clear_trigger = False
|
71
|
+
control.value = None
|
72
|
+
return control
|
73
|
+
|
74
|
+
def get_script(self):
|
75
|
+
"""Генерация кода компонента."""
|
76
|
+
return [self.get_control().render()]
|
77
|
+
|
78
|
+
|
79
|
+
class BoolChoicesFilter(ModifiedChoicesFilter):
|
80
|
+
"""Колоночный фильтр с выпадающим списком значений булевого поля."""
|
81
|
+
|
82
|
+
def __init__(self, field_name, *args, **kwargs):
|
83
|
+
"""Инициализация параметров."""
|
84
|
+
choices = ((None, ''), (True, 'Да'), (False, 'Нет'))
|
85
|
+
|
86
|
+
def lookup(v):
|
87
|
+
"""Формирование lookup для фильтра."""
|
88
|
+
return Q(**{field_name: v}) if v is not None else Q()
|
89
|
+
|
90
|
+
super(BoolChoicesFilter, self).__init__(
|
91
|
+
*args, choices=choices, parser='boolean', lookup=lookup, **kwargs
|
92
|
+
)
|
93
|
+
|
94
|
+
|
95
|
+
class DateFilter(ColumnFilterWithDefaultValue):
|
96
|
+
"""Колоночный фильтр по датам."""
|
97
|
+
|
98
|
+
def create_control(self):
|
99
|
+
"""Создание контрола."""
|
100
|
+
return _create_control_for_field(
|
101
|
+
self.field,
|
102
|
+
**self._field_fabric_params
|
103
|
+
)
|
104
|
+
|
105
|
+
def get_control(self):
|
106
|
+
"""Настройка контрола."""
|
107
|
+
control = self.create_control()
|
108
|
+
control.value = self.default_value
|
109
|
+
control._put_config_value('filterName', self._uid)
|
110
|
+
control._put_config_value('tooltip', self._tooltip or control.label)
|
111
|
+
control.name = self._uid
|
112
|
+
control.allow_blank = True
|
113
|
+
control.hide_clear_trigger = False
|
114
|
+
return control
|
115
|
+
|
116
|
+
def get_script(self):
|
117
|
+
"""Рендер контрола."""
|
118
|
+
return [self.get_control().render()]
|
119
|
+
|
120
|
+
|
121
|
+
class DateFilterByAnnotatedField(DateFilter):
|
122
|
+
"""
|
123
|
+
Колоночный фильтр по аннотируему полю даты.
|
124
|
+
|
125
|
+
Фильтр по полю, которое отсутствует у модели и данные по которому
|
126
|
+
собираются в кварисете через annotate.
|
127
|
+
"""
|
128
|
+
|
129
|
+
def __init__(
|
130
|
+
self, model, field_name, lookup=None, tooltip=None, default_value=None,
|
131
|
+
**field_fabric_params
|
132
|
+
):
|
133
|
+
"""Инициализация параметров."""
|
134
|
+
field_name = field_name.replace('.', '__')
|
135
|
+
self._model = model
|
136
|
+
self._field_name = field_name
|
137
|
+
self._tooltip = tooltip
|
138
|
+
self._field_fabric_params = field_fabric_params
|
139
|
+
self._default_value = default_value
|
140
|
+
self._parser = DeclarativeActionContext._parsers['datetime']
|
141
|
+
if lookup:
|
142
|
+
# шаблонизация лукапа, если петтерн указан
|
143
|
+
if not callable(lookup) and '%s' in lookup:
|
144
|
+
lookup = lookup % field_name
|
145
|
+
else:
|
146
|
+
def lookup(x):
|
147
|
+
return Q(**{field_name: x})
|
148
|
+
self._lookup = lookup
|
149
|
+
|
150
|
+
def create_control(self):
|
151
|
+
"""Создание контрола."""
|
152
|
+
params = {'format': 'd.m.Y'}
|
153
|
+
params.update(**self._field_fabric_params)
|
154
|
+
|
155
|
+
return ext.ExtDateField(**params)
|
@@ -0,0 +1,258 @@
|
|
1
|
+
"""Утилиты для ObjectGrid."""
|
2
|
+
import json
|
3
|
+
|
4
|
+
from m3.actions.urls import (
|
5
|
+
get_url,
|
6
|
+
)
|
7
|
+
from m3_ext.ui import (
|
8
|
+
all_components as ext,
|
9
|
+
)
|
10
|
+
|
11
|
+
|
12
|
+
def add_action_button(label, grid, action, icon_cls, index=None):
|
13
|
+
"""
|
14
|
+
Добавление кнопки в тулбар ObjectGrid'а.
|
15
|
+
|
16
|
+
label - Имя кнопки
|
17
|
+
grid - ObjectGrid
|
18
|
+
action - Action для кнопки
|
19
|
+
icon_cls - Значек кнопки
|
20
|
+
index - Позиция добавления кнопки. По-умолчанию справа.
|
21
|
+
|
22
|
+
Примеры подключения и использования для ObjectPack'а:
|
23
|
+
|
24
|
+
def create_list_window(self, *args, **kwargs):
|
25
|
+
win = super(ObjectPack, self).create_list_window(*args, **kwargs)
|
26
|
+
append_template_globals(win, 'ui-js/object-grid-buttons.js')
|
27
|
+
return win
|
28
|
+
|
29
|
+
def configure_grid(self, grid, *args, **kwargs):
|
30
|
+
super(ObjectPack, self).configure_grid(grid, *args, **kwargs)
|
31
|
+
add_action_button('Печать', grid, self.print_action, Icons.PRINTER)
|
32
|
+
"""
|
33
|
+
action_url = get_url(action)
|
34
|
+
button = ext.ExtButton(
|
35
|
+
text=label,
|
36
|
+
handler=_get_action_handler(action_url),
|
37
|
+
icon_cls=icon_cls)
|
38
|
+
if index is not None:
|
39
|
+
grid.top_bar.items.insert(index, button)
|
40
|
+
else:
|
41
|
+
grid.top_bar.items.append(button)
|
42
|
+
|
43
|
+
|
44
|
+
def add_one_row_button(label, grid, action, icon_cls,
|
45
|
+
dbl_clicked=False, index=None):
|
46
|
+
"""
|
47
|
+
Добавление кнопки в тулбар и popup меню ObjectGrid'а.
|
48
|
+
|
49
|
+
label - Имя кнопки
|
50
|
+
grid - ObjectGrid
|
51
|
+
action - Action для кнопки
|
52
|
+
icon_cls - Значек кнопки
|
53
|
+
dbl_clicked - Вызов действия по даблклику строк
|
54
|
+
index - Позиция добавления кнопки. По-умолчанию справа.
|
55
|
+
|
56
|
+
Примеры подключения и использования для ObjectPack'а:
|
57
|
+
|
58
|
+
def create_list_window(self, *args, **kwargs):
|
59
|
+
win = super(ObjectPack, self).create_list_window(*args, **kwargs)
|
60
|
+
append_template_globals(win, 'ui-js/object-grid-buttons.js')
|
61
|
+
return win
|
62
|
+
|
63
|
+
def configure_grid(self, grid, *args, **kwargs):
|
64
|
+
super(ObjectPack, self).configure_grid(grid, *args, **kwargs)
|
65
|
+
grid.url_edit = None
|
66
|
+
add_one_row_button('Просмотр', grid, self.edit_window_action,
|
67
|
+
Icons.APPLICATION_VIEW_DETAIL, dbl_clicked=True)
|
68
|
+
"""
|
69
|
+
params = _get_one_row_params(label, action, icon_cls)
|
70
|
+
button = ext.ExtButton(**params)
|
71
|
+
if index is not None:
|
72
|
+
grid.top_bar.items.insert(index, button)
|
73
|
+
else:
|
74
|
+
grid.top_bar.items.append(button)
|
75
|
+
|
76
|
+
menuitem = ext.ExtContextMenuItem(**params)
|
77
|
+
grid.context_menu_row.items.append(menuitem)
|
78
|
+
|
79
|
+
if dbl_clicked:
|
80
|
+
grid.dblclick_handler = button.handler
|
81
|
+
grid.handler_dblclick = grid.dblclick_handler
|
82
|
+
|
83
|
+
|
84
|
+
def add_multi_row_button(label, grid, action, icon_cls,
|
85
|
+
confirm_required=False, index=None):
|
86
|
+
"""
|
87
|
+
Добавление кнопки в тулбар и popup меню ObjectGrid'а.
|
88
|
+
|
89
|
+
label - Имя кнопки
|
90
|
+
grid - ObjectGrid
|
91
|
+
action - Action для кнопки
|
92
|
+
icon_cls - Значек кнопки
|
93
|
+
confirm_required - Запрашивать подтверждение действия.
|
94
|
+
index - Позиция добавления кнопки. По-умолчанию справа.
|
95
|
+
|
96
|
+
Примеры подключения и использования для ObjectPack'а:
|
97
|
+
|
98
|
+
def create_list_window(self, *args, **kwargs):
|
99
|
+
win = super(ObjectPack, self).create_list_window(*args, **kwargs)
|
100
|
+
append_template_globals(win, 'ui-js/object-grid-buttons.js')
|
101
|
+
return win
|
102
|
+
|
103
|
+
def configure_grid(self, grid, *args, **kwargs):
|
104
|
+
super(ObjectPack, self).configure_grid(grid, *args, **kwargs)
|
105
|
+
add_multi_row_button(
|
106
|
+
'Переотправить', grid, self.resend_action,
|
107
|
+
'icon_send_message ' + Icons.ARROW_ROTATE_CLOCKWISE
|
108
|
+
)
|
109
|
+
"""
|
110
|
+
params = _get_multirow_params(label, action, icon_cls, confirm_required)
|
111
|
+
button = ext.ExtButton(**params)
|
112
|
+
if index is not None:
|
113
|
+
grid.top_bar.items.insert(index, button)
|
114
|
+
else:
|
115
|
+
grid.top_bar.items.append(button)
|
116
|
+
|
117
|
+
menuitem = ext.ExtContextMenuItem(**params)
|
118
|
+
grid.context_menu_row.items.append(menuitem)
|
119
|
+
|
120
|
+
|
121
|
+
def _get_one_row_params(label, action, icon_cls):
|
122
|
+
action_url = get_url(action)
|
123
|
+
return dict(
|
124
|
+
text=label,
|
125
|
+
icon_cls=icon_cls,
|
126
|
+
handler=_get_one_row_handler(label, action_url),
|
127
|
+
)
|
128
|
+
|
129
|
+
|
130
|
+
def _get_multirow_params(label, action, icon_cls, confirm_required):
|
131
|
+
action_url = get_url(action)
|
132
|
+
return dict(
|
133
|
+
text=label,
|
134
|
+
icon_cls=icon_cls,
|
135
|
+
handler=_get_multi_row_handler(label, action_url, confirm_required),
|
136
|
+
)
|
137
|
+
|
138
|
+
|
139
|
+
def _get_action_handler(url):
|
140
|
+
return """
|
141
|
+
function(){
|
142
|
+
onObjGridAction(objGrid, '%s');
|
143
|
+
}
|
144
|
+
""" % url
|
145
|
+
|
146
|
+
|
147
|
+
def _get_one_row_handler(action_name, url):
|
148
|
+
return """
|
149
|
+
function(){
|
150
|
+
onObjGridOneRecordAction(objGrid, '%s', '%s');
|
151
|
+
}
|
152
|
+
""" % (action_name, url)
|
153
|
+
|
154
|
+
|
155
|
+
def _get_multi_row_handler(action_name, url, confirm_required):
|
156
|
+
return """
|
157
|
+
function(){
|
158
|
+
onObjGridMultiRecordAction(objGrid, '%s', '%s', %s);
|
159
|
+
}
|
160
|
+
""" % (action_name, url, int(bool(confirm_required)))
|
161
|
+
|
162
|
+
|
163
|
+
def column_style_renderer(styles_map, default_style=''):
|
164
|
+
"""Изменение стиля в колонке.
|
165
|
+
|
166
|
+
:param styles_map: словарь карты стилей по значению в колонке
|
167
|
+
:param default_style: стиль по-умолчанию
|
168
|
+
"""
|
169
|
+
func = (
|
170
|
+
"""function (value, metaData, record, rowIndex, colIndex, store) {
|
171
|
+
var styles_map = Ext.util.JSON.decode('%(styles_map)s');
|
172
|
+
metaData.style += styles_map[value] || '%(default_style)s';
|
173
|
+
return value;
|
174
|
+
}""") % {'styles_map': styles_map, 'default_style': default_style}
|
175
|
+
return func
|
176
|
+
|
177
|
+
|
178
|
+
def set_grid_initial(grid, initializers):
|
179
|
+
"""Установка инициализирующих грид функций.
|
180
|
+
|
181
|
+
:param grid: грид.
|
182
|
+
:param initializers: список инициализирующих грид функций
|
183
|
+
|
184
|
+
Пример:
|
185
|
+
|
186
|
+
def configure_grid(self, grid, *args, **kwargs):
|
187
|
+
super(ObjectPack, self).configure_grid(
|
188
|
+
grid, *args, **kwargs)
|
189
|
+
set_grid_initial(grid, (
|
190
|
+
styling_grid_rows(
|
191
|
+
'result_status_code', ResultStatus.styles,
|
192
|
+
'grid-row-yellow-background'
|
193
|
+
),
|
194
|
+
))
|
195
|
+
"""
|
196
|
+
grid_initializers = ''.join(initializers)
|
197
|
+
grid._listeners['added'] = """
|
198
|
+
function() {
|
199
|
+
var grid = Ext.getCmp('%(client_id)s');
|
200
|
+
%(initializers)s
|
201
|
+
}
|
202
|
+
""" % {'initializers': grid_initializers, 'client_id': grid.client_id}
|
203
|
+
|
204
|
+
|
205
|
+
def styling_grid_rows(data_index, styles_map, default_style=''):
|
206
|
+
"""Стилизация строк грида по значению в колонке.
|
207
|
+
|
208
|
+
:param data_index: имя колонки
|
209
|
+
:param styles_map: словарь карты стилей по значению в колонке
|
210
|
+
:param default_style: стиль по-умолчанию
|
211
|
+
"""
|
212
|
+
return """
|
213
|
+
var styles_map = Ext.util.JSON.decode('%(styles_map)s');
|
214
|
+
grid.getView().getRowClass = function(record, rowIndex, rp, ds){
|
215
|
+
return styles_map[
|
216
|
+
record.json.%(data_index)s
|
217
|
+
] || '%(default_style)s';
|
218
|
+
};
|
219
|
+
""" % {
|
220
|
+
'data_index': data_index,
|
221
|
+
'styles_map': json.dumps(styles_map),
|
222
|
+
'default_style': default_style,
|
223
|
+
}
|
224
|
+
|
225
|
+
|
226
|
+
def add_tooltip_to_grid_rows(delegate: str, column_with_text: str) -> str:
|
227
|
+
"""Добавление всплывающей подсказки для строк грида.
|
228
|
+
|
229
|
+
:param delegate: css-класс строк к которым добавляется подсказка
|
230
|
+
:param column_with_text: наименование колонки содержащей текст подсказки
|
231
|
+
"""
|
232
|
+
return """
|
233
|
+
var view = grid.getView();
|
234
|
+
var store = grid.getStore();
|
235
|
+
grid.on('render', function(grid) {
|
236
|
+
grid.tooltip = new Ext.ToolTip({
|
237
|
+
target: view.mainBody,
|
238
|
+
delegate: '%(delegate)s',
|
239
|
+
listeners: {
|
240
|
+
show: function updateTipBody(tooltip) {
|
241
|
+
var rowIndex = view.findRowIndex(tooltip.triggerElement);
|
242
|
+
var text = store.getAt(rowIndex).data['%(column)s'];
|
243
|
+
tooltip.update(text);
|
244
|
+
}
|
245
|
+
}
|
246
|
+
});
|
247
|
+
});
|
248
|
+
""" % {
|
249
|
+
'delegate': delegate,
|
250
|
+
'column': column_with_text,
|
251
|
+
}
|
252
|
+
|
253
|
+
|
254
|
+
def boolean_column_renderer():
|
255
|
+
"""
|
256
|
+
Возвращает JS-рендерер для булевых колонок грида
|
257
|
+
"""
|
258
|
+
return 'function(v){return (!!v ? "Да" : "Нет")}'
|
educommon/utils/ui.py
CHANGED
@@ -13,12 +13,18 @@ from django.db.models import (
|
|
13
13
|
Q,
|
14
14
|
TextField,
|
15
15
|
)
|
16
|
+
from m3 import (
|
17
|
+
ApplicationLogicException,
|
18
|
+
)
|
16
19
|
from m3.actions.context import (
|
17
20
|
ActionContext,
|
18
21
|
)
|
19
22
|
from m3_ext.ui import (
|
20
23
|
all_components as ext,
|
21
24
|
)
|
25
|
+
from m3_ext.ui.base import (
|
26
|
+
BaseExtComponent,
|
27
|
+
)
|
22
28
|
from m3_ext.ui.icons import (
|
23
29
|
Icons,
|
24
30
|
)
|
@@ -394,3 +400,35 @@ class FilterByTextField(FilterByField):
|
|
394
400
|
max_length=self.field.max_length,
|
395
401
|
**self._field_fabric_params
|
396
402
|
)
|
403
|
+
|
404
|
+
|
405
|
+
def append_template_globals(comp, template):
|
406
|
+
"""
|
407
|
+
Добавляет шаблон к BaseExtComponent.template_globals.
|
408
|
+
|
409
|
+
В template_globals допускается использование как строки, так и кортежа
|
410
|
+
со списком. Метод введен для возможности простого добавления нового
|
411
|
+
шаблона к уже существующим без заглядывания в реализацию базовых
|
412
|
+
классов для определения, какого типа ожидается template_globals.
|
413
|
+
|
414
|
+
:param comp: Компонент, которому нужно добавить шаблон для рендеринга
|
415
|
+
:type comp: BaseExtComponent
|
416
|
+
:param template: Имя файла шаблона
|
417
|
+
:type template: str or unicode
|
418
|
+
"""
|
419
|
+
if not isinstance(comp, BaseExtComponent):
|
420
|
+
raise ApplicationLogicException(
|
421
|
+
'Component has no attribute template_globals')
|
422
|
+
if isinstance(comp.template_globals, str):
|
423
|
+
# если template_globals - пустая строка, просто заменяем ее
|
424
|
+
if len(comp.template_globals) == 0:
|
425
|
+
comp.template_globals = template
|
426
|
+
# иначе создаем кортеж из старого значения и добавляемого
|
427
|
+
else:
|
428
|
+
comp.template_globals = (comp.template_globals, template)
|
429
|
+
elif isinstance(comp.template_globals, tuple):
|
430
|
+
comp.template_globals += (template,)
|
431
|
+
elif isinstance(comp.template_globals, list):
|
432
|
+
comp.template_globals.append(template)
|
433
|
+
else:
|
434
|
+
raise ApplicationLogicException('Unknown type of template_globals')
|
educommon/version.conf
CHANGED
@@ -4,8 +4,8 @@
|
|
4
4
|
# нормальной установки обновлений.
|
5
5
|
|
6
6
|
[version]
|
7
|
-
BRANCH = tags/3.
|
8
|
-
VERSION = 3.
|
9
|
-
REVISION =
|
10
|
-
VERSION_DATE =
|
11
|
-
REVISION_DATE =
|
7
|
+
BRANCH = tags/3.6.1
|
8
|
+
VERSION = 3.6.1
|
9
|
+
REVISION = 5c849c3a296d1e7c1b370e73a9a661b385c43293
|
10
|
+
VERSION_DATE = 16.12.2023
|
11
|
+
REVISION_DATE = 16.12.2023
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: educommon
|
3
|
-
Version: 3.
|
3
|
+
Version: 3.6.1
|
4
4
|
Summary: Общая кодовая база для проектов БЦ Образование
|
5
5
|
Home-page: https://stash.bars-open.ru/projects/EDUBASE/repos/educommon
|
6
6
|
Author: BARS Group
|
@@ -34,7 +34,7 @@ Requires-Dist: celery
|
|
34
34
|
Requires-Dist: spyne
|
35
35
|
Requires-Dist: xlsxwriter <1,>=0.9.3
|
36
36
|
Requires-Dist: m3-builder <2,>=1.2
|
37
|
-
Requires-Dist: m3-db-utils >=0.3.
|
37
|
+
Requires-Dist: m3-db-utils >=0.3.11
|
38
38
|
Requires-Dist: m3-django-compat <2,>=1.9.1
|
39
39
|
Requires-Dist: m3-core <3,>=2.2.16
|
40
40
|
Requires-Dist: m3-ui <3,>=2.2.40
|
@@ -1,6 +1,6 @@
|
|
1
1
|
educommon/__init__.py,sha256=fvsBDL7g8HgOTd-JHOh7TSvMcnUauvGVgPuyA2Z9hUI,419
|
2
2
|
educommon/thread_data.py,sha256=n0XtdesP9H92O3rJ8K6fVnJLiHqyJEfh2xpuT36wzxs,61
|
3
|
-
educommon/version.conf,sha256=
|
3
|
+
educommon/version.conf,sha256=CyZ0wpuD4ZOjQH46Sg9nCZPExDS0F8wrAc0C3w-oTOs,448
|
4
4
|
educommon/about/README.rst,sha256=U48UW5jv-8qHyaV56atzzkNMvzHKXVcWSb_NR06PnMo,2685
|
5
5
|
educommon/about/__init__.py,sha256=H1W0IgW-qX9LCZ49GOJzHdmQGHhh-MA6U1xmNx7WnfM,132
|
6
6
|
educommon/about/apps.py,sha256=GrpJAOE2sF0ukWsqugP_WJS88DO4aL-T3kTLprrJrcA,259
|
@@ -29,7 +29,7 @@ educommon/audit_log/actions.py,sha256=hPlnFK8Q8uITA6Rn0CvAyxo76pxVGC1X-g8vzWphgG
|
|
29
29
|
educommon/audit_log/app_meta.py,sha256=fMPgP5S6kDe_lskTEhPVLzjDLDhoVPKCIjUeD4L7sHA,310
|
30
30
|
educommon/audit_log/apps.py,sha256=zHeBEoF8HVNc6YIIQTW-lpEMXjrywnB23uqxXIR9IKg,5033
|
31
31
|
educommon/audit_log/constants.py,sha256=96Gp-rYpt6poKAu8LbXY_0aApdOWYBy09235kAB0rSo,880
|
32
|
-
educommon/audit_log/helpers.py,sha256=
|
32
|
+
educommon/audit_log/helpers.py,sha256=qJLV6yVgf3Z-Mgalc6kGfFvxk8h1L4bTO9fdSL36OPk,738
|
33
33
|
educommon/audit_log/middleware.py,sha256=HkxBh-1RQJnhKqckkXaMbFjJ34WgZGJssbk04wiS3ts,1140
|
34
34
|
educommon/audit_log/models.py,sha256=F4KW-sdGbKxIKdo3GKpPeu66ykO32MxYZ5afvT_Clyg,8305
|
35
35
|
educommon/audit_log/permissions.py,sha256=VB040UAY4_KmqM4ioToHlVHQYSE7OP0qHEUn9bnWUSo,1241
|
@@ -55,7 +55,7 @@ educommon/audit_log/sql/configure_audit_log.sql,sha256=M3QxNKTZbn-uNRxGDvNxE9iJh
|
|
55
55
|
educommon/audit_log/sql/install_audit_log.sql,sha256=SHrZ7WaYxawUKQEpZnj9k4HTU25NvBlxX_POqZ95HU0,14107
|
56
56
|
educommon/audit_log/utils/__init__.py,sha256=qIO8Fre4BMfsKGYi7Q_iFXaKz95d74LxeSOrazhPw1Y,15603
|
57
57
|
educommon/audit_log/utils/operations.py,sha256=Qjdb6FOG3WXbniG4Pau5yDa2Dfn85ivKgSFdw1WPv8A,1661
|
58
|
-
educommon/auth/__init__.py,sha256=
|
58
|
+
educommon/auth/__init__.py,sha256=JnKZNoNGR8H9TIS_6wOlMYTabOuvsxacEQGi1tIJ148,127
|
59
59
|
educommon/auth/rbac/__init__.py,sha256=rMC51R-oN3jCqWIkV1Pkfv5xDNSblwR8Eh-P5q66UDI,329
|
60
60
|
educommon/auth/rbac/actions.py,sha256=25zVmGmYWE2gUt2ak13Ao9pOIZlJx6rgir8eLbj6cMM,26872
|
61
61
|
educommon/auth/rbac/app_meta.py,sha256=tnt65zLTfng6qOrlMByGnxfF3gVLZ6OATNf5gCD3IWI,450
|
@@ -178,7 +178,7 @@ educommon/integration_entities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5
|
|
178
178
|
educommon/integration_entities/consts.py,sha256=XMSR-9Q5cLSXe6Bn0JWFQQ8UfTyJfs7LYT1klj0Xvsc,448
|
179
179
|
educommon/integration_entities/entities.py,sha256=v4QQPb8NeQJMdgxjfEcY9_NmPGasQbRPoA10gZEMAjU,2005
|
180
180
|
educommon/integration_entities/enums.py,sha256=MPS3F402TMUP9wDJXBgNHoktVOf-zM8lAD22QphnLtU,335
|
181
|
-
educommon/integration_entities/helpers.py,sha256=
|
181
|
+
educommon/integration_entities/helpers.py,sha256=ETX_sn6PeKpUK9mBQQ3vtJy143EklRRB6koOQtpc-5I,9888
|
182
182
|
educommon/integration_entities/mixins.py,sha256=wWb2nA8BAtDC3dAn66CkpvGwrW17E_tJE9f6BcI9EXg,1122
|
183
183
|
educommon/ioc/__init__.py,sha256=1X6uu-hwwxbwRZ6g0whIE04GbpXgU7K80QmtE0v-4kQ,4028
|
184
184
|
educommon/logger/__init__.py,sha256=KhXTyv0V96wX_6QShkVrRIk_mqJtDYpeBMBb8PtBl-A,822
|
@@ -203,8 +203,9 @@ educommon/m3/extensions/listeners/delete_check/signals.py,sha256=QnfevsAKpKtOE_E
|
|
203
203
|
educommon/m3/extensions/listeners/delete_check/ui.py,sha256=W3sBsZGbF3q0rxuMUEmycBvFngUh--UQ-77xdjgvDP0,3507
|
204
204
|
educommon/m3/extensions/listeners/delete_check/utils.py,sha256=m4vlKh7zhLbIRV2A8KDS54n1u_t1cL70p6o5E3VwQyQ,2979
|
205
205
|
educommon/objectpack/__init__.py,sha256=TwmrbrumJoH9KjYhbLnKExWmo4A0UQeyNYTK__93Vr8,69
|
206
|
-
educommon/objectpack/actions.py,sha256=
|
206
|
+
educommon/objectpack/actions.py,sha256=KanZUKMl4aUSRPZV-SJB3JwjDTYzuGweI9L5cE1KziI,14735
|
207
207
|
educommon/objectpack/apps.py,sha256=LZl_kQ9s7G9pQ4a5_mWNPN52mFWJ7RGvGIHCHwhKYPo,220
|
208
|
+
educommon/objectpack/filters.py,sha256=je0BIBbwhfVBuGJkeREiFzXuLRMigD8a5okWaY5hsCg,5166
|
208
209
|
educommon/objectpack/ui.py,sha256=SDP3Pjy9rZHdMJtf4Rph5h8BM4fWuxOBrcWsWZ3l-Rk,14752
|
209
210
|
educommon/objectpack/templates/base-grid-window.js,sha256=kq49GGDGPScqLCouIy0-seOimt5eX_l2pAkQNJ0rNCw,437
|
210
211
|
educommon/objectpack/templates/filter-panel.js,sha256=vYw_AxOMRk0ylSBUT46qphilxKkKpaXzT5HfGwwoLYo,1408
|
@@ -268,6 +269,7 @@ educommon/utils/conversion.py,sha256=kEe15TwIH19RmC2mRl1JrrqD8mXgbCAPOYWnkIQXxqQ
|
|
268
269
|
educommon/utils/crypto.py,sha256=3uMk2CP53ZOsJ5Tcb0DLWxmk9ezINZQUsQcqF6j8XR0,2158
|
269
270
|
educommon/utils/date.py,sha256=qE2v_nlxgkU6m1qb90eF2Hyn3NyTVBc9y02u765pcko,16799
|
270
271
|
educommon/utils/misc.py,sha256=HGSoCSyF6hAZaeFTTgA2IkIfMAXIuURqh-rzHVNe0LE,3352
|
272
|
+
educommon/utils/object_grid.py,sha256=mUJd0HJmj4PVljmkwxlR3mQO__YnlLBmAZcFWGxTHLc,9048
|
271
273
|
educommon/utils/patches.py,sha256=Pio9V3bmDH79tTJnM5hi8rwhMEBtbpAg30zPTk5fuN0,1157
|
272
274
|
educommon/utils/plugins.py,sha256=YAD3FM78ihPtyaB_olNM1CoSc5Q5icF_J3A0ivFBFmY,9469
|
273
275
|
educommon/utils/registry.py,sha256=mC_N9aentmznhLFuJn4vyTd3M7d628otWYIx1aM83KY,1995
|
@@ -275,7 +277,7 @@ educommon/utils/seqtools.py,sha256=v621d2X1BO8PQeKIioX4V1BlLTnwIt__GJh9zPF1uI8,5
|
|
275
277
|
educommon/utils/serializer.py,sha256=qdjC6Q6l-bwl9wAzhU6Ujs2_9sc57Z5RA9iNUmzBM74,8787
|
276
278
|
educommon/utils/storage.py,sha256=UwKZX1qnZQgbFn34wLpPnSv_xU6KdpW3M1yz_VxCmww,2883
|
277
279
|
educommon/utils/system.py,sha256=CBdm4t3ng6luvcQANpJiKrJplFmFeM-lX0rKhuII5Ik,2834
|
278
|
-
educommon/utils/ui.py,sha256=
|
280
|
+
educommon/utils/ui.py,sha256=zZU6XIi-lV_xkXv_O9fNcvzAs26PpHtcO-3H-mo-KhU,16082
|
279
281
|
educommon/utils/db/__init__.py,sha256=np9pL-_tv4C6i0iQzTjc-ZGKhaotJK8YSryoPaJ0QQA,7734
|
280
282
|
educommon/utils/db/postgresql.py,sha256=3LOvLqG8QV3hsvo_fupkV26cQmSf0WNBhgpVcfs-lWc,2820
|
281
283
|
educommon/utils/fonts/Arial.ttf,sha256=NcDzVZ2NtWnjbDEJW4pg1EFkPZX1kTneQOI_ragZuDM,275572
|
@@ -323,8 +325,8 @@ educommon/ws_log/smev/exceptions.py,sha256=lmy7o2T3dJkqgIhG07qyh5yPqO3qZAYABuT4J
|
|
323
325
|
educommon/ws_log/templates/report/smev_logs.xlsx,sha256=nnYgB0Z_ix8HoxsRICjsZfFRQBdra-5Gd8nWhCxTjYg,10439
|
324
326
|
educommon/ws_log/templates/ui-js/smev-logs-list-window.js,sha256=AGup3D8GTJSY9WdDPj0zBJeYQBFOmGgcbxPOJbKK-nY,513
|
325
327
|
educommon/ws_log/templates/ui-js/smev-logs-report-setting-window.js,sha256=nQ7QYK9frJcE7g7kIt6INg9TlEEJAPPayBJgRaoTePA,1103
|
326
|
-
educommon-3.
|
327
|
-
educommon-3.
|
328
|
-
educommon-3.
|
329
|
-
educommon-3.
|
330
|
-
educommon-3.
|
328
|
+
educommon-3.6.1.dist-info/METADATA,sha256=j7fq3ajpRnYwfk1aYrW_xomuaEyvu5SBE8ePinJisTY,1736
|
329
|
+
educommon-3.6.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
330
|
+
educommon-3.6.1.dist-info/dependency_links.txt,sha256=RNlr4t-BxZRm7e_IfVo1ikr5ln-7viimzLHvQMO1C_Q,43
|
331
|
+
educommon-3.6.1.dist-info/top_level.txt,sha256=z5fbW7bz_0V1foUm_FGcZ9_MTpW3N1dBN7-kEmMowl4,10
|
332
|
+
educommon-3.6.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|