Пример #1
0
    def drag_item(self, ids, dest_id):
        # В корень нельзя кидать простые элементы
        if dest_id < 1:
            return OperationResult.by_message(
                u'Нельзя перемещать элементы в корень справочника!')

        # Из грида в дерево одновременно
        # могут быть перенесены несколько элементов
        # Их id разделены запятыми
        for id in ids:
            row = self.get_row(id)
            row.parent_id = dest_id
            row.save()
        return OperationResult()
Пример #2
0
    def run(self, request, context):
        try:
            result = self.parent.get_row(context.id)
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        return PreJsonResult(result)
Пример #3
0
    def run(self, request, context):
        try:
            if not context.id and self.parent.add_window:
                obj = utils.bind_request_form_to_object(
                    request, self.parent.get_row, self.parent.add_window)
            else:
                obj = utils.bind_request_form_to_object(
                    request, self.parent.get_row, self.parent.edit_window)
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        # Проверка корректности полей сохраняемого объекта
        result = self.parent.validate_row(obj, request)
        if result:
            assert isinstance(result, ActionResult)
            return result

        result = self.parent.save_row(obj)
        if isinstance(result, OperationResult) and result.success is True:
            # узкое место. после того, как мы переделаем работу экшенов,
            # имя параметра с идентификатором запси может уже называться не
            # id
            if 'm3_audit' in settings.INSTALLED_APPS:
                AuditManager().write('dict-changes',
                                     user=request.user,
                                     model_object=obj,
                                     type='new' if not context.id else 'edit')
            context.id = obj.id
        return result
Пример #4
0
 def delete_row(self, objs):
     # Такая реализация обусловлена тем,
     # что IntegrityError невозможно отловить
     # до завершения транзакции, и приходится оборачивать транзакцию.
     @transaction.commit_on_success
     def delete_row_in_transaction(self, objs):
         message = ''
         if len(objs) == 0:
             message = u'Элемент не существует в базе данных.'
         else:
             for obj in objs:
                 if (
                     isinstance(obj, BaseObjectModel) or
                     (hasattr(obj, 'safe_delete') and
                         callable(obj.safe_delete))
                 ):
                     try:
                         obj.safe_delete()
                     except RelatedError, e:
                         message = e.args[0]
                 else:
                     if not safe_delete(obj):
                         message = (
                             u'Не удалось удалить элемент %s. '
                             u'Возможно на него есть ссылки.'
                         ) % obj.id
                         break
         return OperationResult.by_message(message)
Пример #5
0
    def run(self, request, context):
        try:
            if not context.id and self.parent.add_window:
                obj = utils.bind_request_form_to_object(
                    request, self.parent.get_row, self.parent.add_window)
            else:
                obj = utils.bind_request_form_to_object(
                    request, self.parent.get_row, self.parent.edit_window)
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        # Проверка корректности полей сохраняемого объекта
        result = self.parent.validate_row(obj, request)
        if result:
            assert isinstance(result, ActionResult)
            return result

        result = self.parent.save_row(obj)
        if isinstance(result, OperationResult) and result.success is True:
            # узкое место. после того, как мы переделаем работу экшенов,
            # имя параметра с идентификатором запси может уже называться не
            # id
            if 'm3_audit' in settings.INSTALLED_APPS:
                AuditManager().write(
                    'dict-changes',
                    user=request.user,
                    model_object=obj,
                    type='new' if not context.id else 'edit')
            context.id = obj.id
        return result
Пример #6
0
    def delete_node(self, obj):
        """
        Удаление группы справочника.
        Нельзя удалять группу если у нее есть подгруппы,
        или если в ней есть элементы. Но даже после этого удалять
        группу можно только прямым запросом, т.к. мы не знаем заранее,
        кто на нее может ссылаться и кого зацепит каскадное удаление джанги.
        """
        message = ''
        if obj is None:
            message = u'Группа не существует в базе данных.'
        elif self.tree_model.objects.filter(**{
                self.tree_parent_field: obj
        }).exists():
            message = u'Нельзя удалить группу содержащую в себе другие группы.'
        elif self.list_model and self.list_model.objects.filter(
                **{
                    self.list_parent_field: obj
                }).exists():
            message = u'Нельзя удалить группу содержащую в себе элементы.'
        elif not safe_delete(obj):
            message = (
                u'Не удалось удалить группу. Возможно на неё есть ссылки.')

        return OperationResult.by_message(message)
Пример #7
0
    def run(self, request, context):
        if context.report_id:
            mutex = CreadocMutex(context.report_id)

            if not mutex.is_free():
                mutex.release()

        return OperationResult()
Пример #8
0
    def run(self, request, context):
        base = self.parent
        is_get_data = context.isGetData
        # Получаем объект по id
        try:
            obj = base.get_row(context.id)
        except base._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        # Разница между новым и созданным объектов в том,
        # что у нового нет id или он пустой
        create_new = True
        if isinstance(obj, dict) and obj.get('id') is not None:
            create_new = False
        elif hasattr(obj, 'id') and getattr(obj, 'id') is not None:
            create_new = False
        if create_new and base.add_window:
            win = utils.bind_object_from_request_to_form(
                request, base.get_row, base.add_window)
        else:
            win = utils.bind_object_from_request_to_form(
                request, base.get_row, base.edit_window)

        if not win.title:
            win.title = base.title
        win.form.url = base.save_action.get_absolute_url()
        # укажем адрес для чтения данных
        win.data_url = base.edit_window_action.get_absolute_url()

        # проверим право редактирования
        if not self.parent.has_sub_permission(request.user,
                                              self.parent.PERM_EDIT, request):
            exclude_list = ['close_btn', 'cancel_btn']
            win.make_read_only(True, exclude_list)

        # У окна может быть процедура доп. конфигурации
        # под конкретный справочник
        if (hasattr(win, 'configure_for_dictpack')
                and callable(win.configure_for_dictpack)):
            win.configure_for_dictpack(action=self,
                                       pack=self.parent,
                                       request=request,
                                       context=context)

        if not is_get_data:
            # если запрашивали не данные - вернем окно
            return ExtUIScriptResult(base.get_edit_window(win))
        else:
            # если просили данные, то выжмем их из окна обратно в объект,
            # т.к. в окне могли быть и другие данных (не из этого объекта)
            data_object = {}
            # т.к. мы не знаем какие поля должны быть у объекта - создадим
            # все, которые есть на форме
            all_fields = win.form._get_all_fields(win)
            for field in all_fields:
                data_object[field.name] = None
            win.form.to_object(data_object)
            return PreJsonResult({'success': True, 'data': data_object})
Пример #9
0
    def run(self, request, context):
        template = request.FILES.get('file_template')
        if not template:
            raise ApplicationLogicException(
                u'Не удалось загрузить шаблон')

        load_template(template, request.user)

        return OperationResult()
Пример #10
0
 def drag_node(self, id, dest_id):
     node = self.get_node(id)
     # Если id узла на который кидаем <1, значит это корень справочника
     if dest_id < 1:
         node.parent_id = None
     else:
         node.parent_id = dest_id
     node.save()
     return OperationResult()
Пример #11
0
    def run(self, request, context):
        base = self.parent
        id = getattr(context, base.contextTreeIdName)
        try:
            obj = self.parent.get_node(id)
        except self.parent._group_nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % id)

        return self.parent.delete_node(obj)
Пример #12
0
    def run(self, request, context):
        base = self.parent
        is_get_data = context.isGetData
        # Получаем объект по id
        try:
            obj = base.get_row(context.id)
        except base._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        # Разница между новым и созданным объектов в том,
        # что у нового нет id или он пустой
        create_new = True
        if isinstance(obj, dict) and obj.get('id') is not None:
            create_new = False
        elif hasattr(obj, 'id') and getattr(obj, 'id') is not None:
            create_new = False
        if create_new and base.add_window:
            win = utils.bind_object_from_request_to_form(
                request, base.get_row, base.add_window)
        else:
            win = utils.bind_object_from_request_to_form(
                request, base.get_row, base.edit_window)

        if not win.title:
            win.title = base.title
        win.form.url = base.save_action.get_absolute_url()
        # укажем адрес для чтения данных
        win.data_url = base.edit_window_action.get_absolute_url()

        # проверим право редактирования
        if not self.parent.has_sub_permission(
                request.user, self.parent.PERM_EDIT, request):
            exclude_list = ['close_btn', 'cancel_btn']
            win.make_read_only(True, exclude_list)

        # У окна может быть процедура доп. конфигурации
        # под конкретный справочник
        if (hasattr(win, 'configure_for_dictpack') and
                callable(win.configure_for_dictpack)):
            win.configure_for_dictpack(action=self, pack=self.parent,
                                       request=request, context=context)

        if not is_get_data:
            # если запрашивали не данные - вернем окно
            return ExtUIScriptResult(base.get_edit_window(win))
        else:
            # если просили данные, то выжмем их из окна обратно в объект,
            # т.к. в окне могли быть и другие данных (не из этого объекта)
            data_object = {}
            # т.к. мы не знаем какие поля должны быть у объекта - создадим
            # все, которые есть на форме
            all_fields = win.form._get_all_fields(win)
            for field in all_fields:
                data_object[field.name] = None
            win.form.to_object(data_object)
            return PreJsonResult({'success': True, 'data': data_object})
Пример #13
0
    def run(self, request, context):
        try:
            obj = utils.bind_request_form_to_object(request, self.parent.get_row, self.parent.edit_window)
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        result = self.parent.validate_row(obj, request)
        if result:
            assert isinstance(result, ActionResult)
            return result
        return self.parent.save_row(obj)
Пример #14
0
    def run(self, request, context):
        CreadocReportDataSource.objects.filter(
            report__id=context.report_id
        ).delete()

        for row in context.rows:
            record = CreadocReportDataSource()
            record.report_id = context.report_id
            record.source_uid = row
            record.save()

        return OperationResult()
Пример #15
0
    def run(self, request, context):
        deleted = 0
        protected = 0

        for row_id in context.row_id:
            mutex = CreadocMutex(row_id)

            if not mutex.is_free():
                protected += 1
                continue

            try:
                report = CreadocReport.objects.get(pk=row_id)
            except CreadocReport.DoesNotExist:
                raise ApplicationLogicException((
                    u'Шаблон с id={} отсутствует!'
                ).format(row_id))

            # Пробуем удалить шаблон. Если отсутствует, то пропускаем.
            try:
                os.remove(report.path)
            except OSError:
                pass

            report.delete()

            deleted += 1

        if protected:
            result = OperationResult(message=(
                u'Удалено записей: {}<br>'
                u'Используется другими пользователями: {}'
            ).format(deleted, protected))
        else:
            result = OperationResult()

        return result
Пример #16
0
    def run(self, request, context):
        # Создаем форму для биндинга к ней
        win = self.parent.edit_node_window()
        win.form.bind_to_request(request)

        # Получаем наш объект по id
        try:
            obj = self.parent.get_node(context.id)
        except self.parent._group_nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        # Биндим форму к объекту
        win.form.to_object(obj)
        result = self.parent.validate_node(obj, request)
        if result:
            assert isinstance(result, ActionResult)
            return result

        return self.parent.save_node(obj)
Пример #17
0
    def run(self, request, context):
        """
        Удаляться одновременно могут несколько объектов. Их ключи
        приходят разделенные запятыми.
        """
        ids = utils.extract_int_list(request, 'id')
        try:
            objs = [self.parent.get_row(id) for id in ids]
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % id)

        result = self.parent.delete_row(objs)
        if (isinstance(result, OperationResult) and result.success is True
                and 'm3_audit' in settings.INSTALLED_APPS):
            for obj in objs:
                AuditManager().write('dict-changes',
                                     user=request.user,
                                     model_object=obj,
                                     type='delete')
        return result
Пример #18
0
    def delete_node(self, obj):
        """
        Удаление группы справочника.
        Нельзя удалять группу если у нее есть подгруппы,
        или если в ней есть элементы. Но даже после этого удалять
        группу можно только прямым запросом, т.к. мы не знаем заранее,
        кто на нее может ссылаться и кого зацепит каскадное удаление джанги.
        """
        message = ''
        if obj is None:
            message = u'Группа не существует в базе данных.'
        elif self.tree_model.objects.filter(
                **{self.tree_parent_field: obj}).exists():
            message = u'Нельзя удалить группу содержащую в себе другие группы.'
        elif self.list_model and self.list_model.objects.filter(
                **{self.list_parent_field: obj}).exists():
            message = u'Нельзя удалить группу содержащую в себе элементы.'
        elif not safe_delete(obj):
            message = (
                u'Не удалось удалить группу. Возможно на неё есть ссылки.')

        return OperationResult.by_message(message)
Пример #19
0
    def run(self, request, context):
        """
        Удаляться одновременно могут несколько объектов. Их ключи
        приходят разделенные запятыми.
        """
        ids = utils.extract_int_list(request, 'id')
        try:
            objs = [self.parent.get_row(id) for id in ids]
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % id)

        result = self.parent.delete_row(objs)
        if (isinstance(result, OperationResult) and
                result.success is True and
                'm3_audit' in settings.INSTALLED_APPS):
            for obj in objs:
                AuditManager().write(
                    'dict-changes',
                    user=request.user,
                    model_object=obj,
                    type='delete')
        return result
Пример #20
0
    def run(self, request, context):
        base = self.parent
        try:
            win = utils.bind_object_from_request_to_form(request, base.get_row, base.edit_window)
        except self.parent._nofound_exception:
            return OperationResult.by_message(MSG_DOESNOTEXISTS % context.id)

        if not win.title:
            win.title = base.title
        win.form.url = base.save_row_action.get_absolute_url()

        # проверим право редактирования
        if not self.parent.has_perm(request, self.parent.PERM_EDIT):
            win.make_read_only(
                access_off=True, exclude_list=['cancel_btn', 'close_btn'])

        # У окна может быть процедура доп. конфигурации под конкретный справочник
        if hasattr(win, 'configure_for_dictpack') and callable(win.configure_for_dictpack):
            win.configure_for_dictpack(action=self, pack=self.parent,
                                       request=request, context=context)

        return ExtUIScriptResult(base.get_edit_window(win))
Пример #21
0
    def run(self, request, context):
        try:
            report = CreadocReport.objects.get(pk=context.report_id)
        except CreadocReport.DoesNotExist:
            raise ApplicationLogicException((
                u'Шаблон с id={} отсутствует!'
            ).format(context.report_id))

        # Извлекаем все подключенные к шаблону источники данных
        report_sources = CreadocReportDataSource.objects.filter(report=report)
        sources = map(attrgetter('source_uid'), report_sources.iterator())

        name = '{}.creadoc'.format(report.guid)
        zip_path = os.path.join(settings.CREADOC_REPORTS_ROOT, name)

        # Формирование архива с шаблоном
        with ZipFile(zip_path, 'w') as f:
            # Сохранение шаблона
            f.write(report.path, 'report.json')
            # Сохранение списка используемых источников данных
            f.writestr('sources.json', json.dumps(sources))
            # Сохранение мета-информации о шаблоне
            f.writestr('META.json', json.dumps({
                'name': report.name,
                'guid': report.guid,
                'datetime': datetime.datetime.now().strftime(
                    '%Y-%m-%d %H:%M:%S'),
            }))

        file_url = settings.CREADOC_REPORTS_URL + name

        safe_js_handler = '''function() {
            var iframe = document.createElement("iframe");
            iframe.src = '%s';
            iframe.style.display = "none";
            document.body.appendChild(iframe);
        }''' % file_url

        return OperationResult(code=safe_js_handler)
Пример #22
0
 def save_node(self, obj):
     obj.save()
     return OperationResult(success=True)
Пример #23
0
class BaseTreeDictionaryModelActions(BaseTreeDictionaryActions):
    """
    Класс реализует действия над иерархическим справочником,
    основанном на моделе
    """
    # Признак возвращения всех узлов дерева
    ALL_ROWS = -1

    # Поля для поиска по умолчанию.
    DEFAULT_FILTER_FIELDS = ['code', 'name']

    # Настройки для модели дерева
    tree_model = None  # Сама модель дерева
    tree_filter_fields = []  # Поля по которым производится поиск в дереве
    tree_columns = []  # Список из кортежей с параметрами выводимых в дерево колонок
    tree_parent_field = 'parent'  # Имя поля ссылающегося на группу
    tree_readonly = False  # Если истина, то адреса экшенов дереву не назначаются
    tree_order_field = ''
    tree_drag_and_drop = True  # Разрешает перетаскивание внутри дерева

    # Настройки модели списка
    list_model = None  # Не обязательная модель списка связанного с деревом
    list_columns = []  # Список из кортежей с параметрами выводимых в грид колонок
    filter_fields = []  # Поля по которым производится поиск в списке
    list_parent_field = 'parent'  # Имя поля ссылающегося на группу
    list_readonly = False  # Если истина, то адреса экшенов гриду не назначаются
    list_drag_and_drop = True  # Разрешает перетаскивание элементов из грида в другие группы дерева
    list_order_field = ''
    list_paging = True

    # Порядок сортировки элементов списка. Работает следующим образом:
    # 1. Если в list_columns модели списка есть поле code,
    #   то устанавливается сортировка по возрастанию этого поля;
    # 2. Если в list_columns модели списка нет поля code, но есть поле name,
    #   то устанавливается сортировка по возрастанию поля name;
    # Пример list_sort_order = ['code', '-name']
    list_sort_order = []
    tree_sort_order = None

    def __init__(self):
        super(BaseTreeDictionaryModelActions, self).__init__()
        # Установка значений по умолчанию для поиска и сортировки
        if self.list_model:
            self.filter_fields = self._default_list_search_filter()
            self.list_sort_order = self._default_order()
            self._nofound_exception = self.list_model.DoesNotExist

        if self.tree_model:
            self.tree_filter_fields = self._default_tree_search_filter()
            self._group_nofound_exception = self.tree_model.DoesNotExist

    def get_nodes(self, parent_id, filter, branch_id = None):
        """
        Метод получения списка узлов дерева, которые
        """
        # parent_id - это элемент, который раскрывается,
        # поэтому для него фильтр ставить не надо, иначе фильтруем
        # branch_id - это элемент ограничивающий дерево,
        # т.е. должны возвращаться только дочерние ему элементы
        if filter and not parent_id:
            filter_dict = utils.create_search_filter(
                filter, self.tree_filter_fields)
            nodes = utils.fetch_search_tree(
                self.tree_model, filter_dict, branch_id)
        else:
            if branch_id and hasattr(self.tree_model, 'get_descendants'):
                branch_node = self.tree_model.objects.get(id=branch_id)
                if parent_id:
                    query = branch_node.get_descendants().filter(
                        parent=parent_id)
                else:
                    query = branch_node.get_children()
            else:
                query = self.tree_model.objects.filter(parent=parent_id)
            query = utils.apply_sort_order(
                query, self.tree_columns, self.tree_sort_order)
            nodes = list(query)
            # Если имеем дело с листом, нужно передавать параметр leaf = true
            for node in nodes:
                if not self.tree_model.objects.filter(parent=node.id).exists():
                    node.leaf = 'true'

        # генерируем сигнал о том, что узлы дерева подготовлены
        nodes_prepared.send(sender=self.__class__, nodes=nodes)
        return nodes

    def get_rows(self, parent_id, offset, limit, filter):
        # если справочник состоит только из дерева и у него просят запись,
        # то надо брать из модели дерева
        # TODO: возможно это не надо было делать - раз не туда обратились,
        # значит сами виноваты
        if self.list_model:
            query = None
            if parent_id == BaseTreeDictionaryModelActions.ALL_ROWS:
                # отображаются все данные
                query = self.list_model.objects
            else:
                # отображаются данные с фильтрацией по значению parent_id
                query = self.list_model.objects.filter(
                    **{self.list_parent_field: parent_id})

            # Подтягиваем группу, т.к. при сериализации она требуется
            query = query.select_related(self.list_parent_field)
            query = utils.apply_sort_order(
                query, self.list_columns, self.list_sort_order)
            query = utils.apply_search_filter(
                query, filter, self.filter_fields)

            # Для работы пейджинга нужно передавать общее количество записей

            total = query.count()
            # Срез данных для страницы
            if limit > 0:
                query = query[offset: offset + limit]

            result = {'rows': list(query.all()), 'total': total}
            return result
        else:
            return self.get_nodes(parent_id, filter)

    def _get_model_fieldnames(self, model):
        """
        Возвращает имена всех полей модели
        """
        return [field.attname for field in model._meta.local_fields]

    def _default_order(self):
        """
        Устанавливаем параметры сортировки
        по умолчанию 'code' и 'name' в случае,
        если у модели есть такие поля
        """
        filter_order = self.list_sort_order
        if not filter_order:
            filter_order = []
            all_fields = self._get_model_fieldnames(self.list_model)
            filter_order.extend([
                field for field in ('code', 'name', 'id')
                if field in all_fields
            ])
        return filter_order

    def _default_tree_search_filter(self):
        """
        Если поля для поиска не заданы, то возвращает список из полей модели
        по которым будет производиться поиск.
        По умолчанию берутся код и наименование
        """
        if not self.tree_filter_fields:
            assert self.tree_model, 'Tree model is not defined!'
            for field_name in self._get_model_fieldnames(self.tree_model):
                if field_name in self.DEFAULT_FILTER_FIELDS:
                    self.tree_filter_fields.append(field_name)

        return self.tree_filter_fields

    def _default_list_search_filter(self):
        """
        Если поля для поиска не заданы, то возвращает список из полей модели
        по которым будет производиться поиск.
        По умолчанию берутся код и наименование
        """
        if not self.filter_fields:
            assert self.list_model, 'List model is not defined!'
            for field_name in self._get_model_fieldnames(self.list_model):
                if field_name in self.DEFAULT_FILTER_FIELDS:
                    self.filter_fields.append(field_name)

        return self.filter_fields

    def get_nodes_like_rows(self, filter, branch_id=None):
        """
        Возвращаются узлы дерева, предствленные в виде общего списка
        """
        # branch_id - это элемент ограничивающий дерево,
        # т.е. должны возвращаться только дочерние ему элементы
        if filter:
            filter_dict = utils.create_search_filter(
                filter, self.tree_filter_fields)
            if branch_id and hasattr(self.tree_model, 'get_descendants'):
                branch_node = self.tree_model.objects.get(id=branch_id)
                nodes = branch_node.get_descendants().filter(
                    filter_dict).select_related('parent')
            else:
                nodes = self.tree_model.objects.filter(
                    filter_dict).select_related('parent')
        else:
            if branch_id and hasattr(self.tree_model, 'get_descendants'):
                branch_node = self.tree_model.objects.get(id=branch_id)
                nodes = branch_node.get_descendants()
            else:
                nodes = self.tree_model.objects.all()

        # Для работы пейджинга нужно передавать общее количество записей
        total = len(nodes)
        result = {'rows': list(nodes), 'total': total}
        return result

    def _get_obj(self, model, id):
        """
        Возвращает запись заданной модели model по id
        Если id нет, значит нужно создать новый объект
        """
        assert isinstance(id, int)
        if id == 0:
            obj = model()
        else:
            obj = model.objects.get(id=id)
        return obj

    def get_node(self, id=0):
        return self._get_obj(self.tree_model, id)

    def get_row(self, id=0):
        # если справочник состоит только из дерева и у него просят запись,
        # то надо брать из модели дерева
        # TODO: это надо было для элемента выбора из справочника
        # - он не знает откуда ему взять запись и всегда вызывает get_row.
        # может надо было как-то по-другому это решить
        if self.list_model:
            return self._get_obj(self.list_model, id)
        else:
            return self.get_node(id)

    def save_row(self, obj):
        obj.save()
        return OperationResult(success=True)

    def save_node(self, obj):
        obj.save()
        return OperationResult(success=True)

    def delete_row(self, objs):
        # Такая реализация обусловлена тем,
        # что IntegrityError невозможно отловить
        # до завершения транзакции, и приходится оборачивать транзакцию.
        @transaction.commit_on_success
        def delete_row_in_transaction(self, objs):
            message = ''
            if len(objs) == 0:
                message = u'Элемент не существует в базе данных.'
            else:
                for obj in objs:
                    if (
                        isinstance(obj, BaseObjectModel) or
                        (hasattr(obj, 'safe_delete') and
                            callable(obj.safe_delete))
                    ):
                        try:
                            obj.safe_delete()
                        except RelatedError, e:
                            message = e.args[0]
                    else:
                        if not safe_delete(obj):
                            message = (
                                u'Не удалось удалить элемент %s. '
                                u'Возможно на него есть ссылки.'
                            ) % obj.id
                            break
            return OperationResult.by_message(message)
        # Тут пытаемся поймать ошибку из транзакции.
        try:
            return delete_row_in_transaction(self, objs)
        except Exception, e:
            # Встроенный в Django IntegrityError не генерируется.
            # Кидаются исключения специфичные для каждого драйвера БД.
            # Но по спецификации PEP 249 все они называются IntegrityError
            if e.__class__.__name__ == 'IntegrityError':
                message = (
                    u'Не удалось удалить элемент. '
                    u'Возможно на него есть ссылки.'
                )
                return OperationResult.by_message(message)
            else:
                # все левые ошибки выпускаем наверх
                raise
Пример #24
0
class BaseDictionaryModelActions(BaseDictionaryActions):
    """
    Класс, который реализует действия со справочником,
    записи которого являются моделями.
    """
    # Настройки вида справочника (задаются конечным разработчиком)
    model = None
    # Список полей модели по которым будет идти поиск
    filter_fields = []

    # Порядок сортировки элементов списка. Работает следующим образом:
    # 1. Если в list_columns модели списка есть поле
    # code, то устанавливается сортировка по возрастанию этого поля;
    # 2. Если в list_columns модели списка нет поля code, но
    # есть поле name, то устанавливается сортировка по возрастанию поля name;
    # Пример list_sort_order = ['code', '-name']
    list_sort_order = None

    def __init__(self):
        super(BaseDictionaryModelActions, self).__init__()
        if self.model:
            self._nofound_exception = self.model.DoesNotExist

    def get_rows_modified(self,
                          offset,
                          limit,
                          filter,
                          user_sort='',
                          request=None,
                          context=None):
        '''
        Возвращает данные для грида справочника
        '''
        sort_order = user_sort.split(
            ',') if user_sort else self.list_sort_order
        filter_fields = self._default_filter()
        query = self.model.objects.all()
        query = utils.apply_sort_order(query, self.list_columns, sort_order)
        query = utils.apply_search_filter(query, filter, filter_fields)
        if (hasattr(self, 'modify_rows_query')
                and callable(self.modify_rows_query)):
            query = self.modify_rows_query(query, request, context)
        total = query.count()
        if limit > 0:
            query = query[offset:offset + limit]
        result = {'rows': list(query), 'total': total}
        return result

    def get_rows(self, offset, limit, filter, user_sort=''):
        sort_order = user_sort.split(
            ',') if user_sort else self.list_sort_order
        filter_fields = self._default_filter()
        query = utils.apply_sort_order(self.model.objects, self.list_columns,
                                       sort_order)
        query = utils.apply_search_filter(query, filter, filter_fields)
        total = query.count()
        if limit > 0:
            query = query[offset:offset + limit]
        result = {'rows': list(query.all()), 'total': total}
        return result


#    def modify_rows_query(self, query, request, context):
#        '''
#        Модифицирует запрос на получение данных.
#        Данный метод необходимо определить в
#        дочерних классах.
#        '''
#        return query

    def get_row(self, id):
        assert isinstance(id, int)
        # Если id нет, значит нужно создать новый объект
        if id == 0:
            record = self.model()
        else:
            record = self.model.objects.get(id=id)
        return record

    @transaction.commit_on_success
    def save_row(self, obj):
        obj.save()
        return OperationResult(success=True)

    def delete_row(self, objs):
        # Такая реализация обусловлена тем,
        # что IntegrityError невозможно отловить
        # до завершения транзакции, и приходится оборачивать транзакцию.
        @transaction.commit_on_success
        def delete_row_in_transaction(self, objs):
            message = ''
            if len(objs) == 0:
                message = u'Элемент не существует в базе данных.'
            else:
                for obj in objs:
                    if (isinstance(obj, BaseObjectModel)
                            or (hasattr(obj, 'safe_delete')
                                and callable(obj.safe_delete))):
                        try:
                            obj.safe_delete()
                        except RelatedError, e:
                            message = e.args[0]
                    else:
                        if not safe_delete(obj):
                            message = (u'Не удалось удалить элемент %s. '
                                       u'Возможно на него есть ссылки.' %
                                       obj.id)
                            break
            return OperationResult.by_message(message)

        # Тут пытаемся поймать ошибку из транзакции.
        try:
            return delete_row_in_transaction(self, objs)
        except Exception, e:
            # Встроенный в Django IntegrityError
            # не генерируется. Кидаются исключения
            # специфичные для каждого драйвера БД.
            # Но по спецификации PEP 249 все они
            # называются IntegrityError
            if e.__class__.__name__ == 'IntegrityError':
                message = (u'Не удалось удалить элемент. '
                           u'Возможно на него есть ссылки.')
                return OperationResult.by_message(message)
            else:
                # все левые ошибки выпускаем наверх
                raise