diff --git a/sapl/api/core/__init__.py b/sapl/api/core/__init__.py index b4785aa40..438b993a8 100644 --- a/sapl/api/core/__init__.py +++ b/sapl/api/core/__init__.py @@ -20,7 +20,7 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet -from sapl.api.forms import SaplFilterSetMixin +from sapl.api.core.filters import SaplFilterSetMixin from sapl.api.permissions import SaplModelPermissions from sapl.api.serializers import ChoiceSerializer, ParlamentarSerializer,\ ParlamentarEditSerializer, ParlamentarResumeSerializer @@ -56,6 +56,7 @@ class SaplApiViewSetConstrutor(): # Carrega todas as classes de sapl.api.serializers que possuam # "Serializer" como Sufixo. serializers_classes = inspect.getmembers(serializers) + serializers_classes = {i[0]: i[1] for i in filter( lambda x: x[0].endswith('Serializer'), serializers_classes @@ -82,7 +83,8 @@ class SaplApiViewSetConstrutor(): serializer_name, rest_serializers.ModelSerializer) # Caso Exista, pega a classe sapl.api.forms.{model}FilterSet - # ou utiliza a base definida em sapl.forms.SaplFilterSetMixin + # ou utiliza a base definida em + # sapl.api.core.filters.SaplFilterSetMixin filter_name = f'{object_name}FilterSet' _filterset_class = filters_classes.get( filter_name, SaplFilterSetMixin) @@ -127,7 +129,7 @@ class SaplApiViewSetConstrutor(): class Meta(_meta_filterset): if not hasattr(_meta_filterset, 'model'): model = _model - + # Define uma classe padrão ModelViewSet de DRF class ModelSaplViewSet(SaplApiViewSetConstrutor.SaplApiViewSet): queryset = _model.objects.all() diff --git a/sapl/api/core/filters.py b/sapl/api/core/filters.py new file mode 100644 index 000000000..cc4a601c1 --- /dev/null +++ b/sapl/api/core/filters.py @@ -0,0 +1,105 @@ + +from collections import OrderedDict + +from django.conf import settings +from django.db.models.fields import DateTimeField, DateField +from django.db.models.fields.files import FileField +from django.template.defaultfilters import capfirst +import django_filters +from django_filters.constants import ALL_FIELDS +from django_filters.filters import CharFilter +from django_filters.filterset import BaseFilterSet, FilterSetMetaclass, \ + FilterSet +from django_filters.utils import resolve_field, get_all_model_fields + + +class SaplFilterSetMixin(FilterSet): + + o = CharFilter(method='filter_o') + + class Meta: + fields = '__all__' + filter_overrides = { + FileField: { + 'filter_class': django_filters.CharFilter, + 'extra': lambda f: { + 'lookup_expr': 'exact', + }, + }, + } + + def filter_o(self, queryset, name, value): + try: + return queryset.order_by( + *map(str.strip, value.split(','))) + except: + return queryset + + @classmethod + def get_fields(cls): + model = cls._meta.model + fields_model = get_all_model_fields(model) + fields_filter = cls._meta.fields + exclude = cls._meta.exclude + + if exclude is not None and fields_filter is None: + fields_filter = ALL_FIELDS + + fields = fields_filter if isinstance(fields_filter, dict) else {} + if not isinstance(fields_filter, (dict, str)): + for f in fields_filter: + fields[f] = ['exact'] + + for f_str in fields_model: + if f_str not in fields: + f = model._meta.get_field(f_str) + fields[f_str] = [] + + def get_keys_lookups(cl, sub_f): + r = [] + for lk, lv in cl.items(): + if lk == 'contained_by': + continue + sflk = f'{sub_f}{"__" if sub_f else ""}{lk}' + r.append(sflk) + + if hasattr(lv, 'class_lookups'): + r += get_keys_lookups(lv.class_lookups, sflk) + + if hasattr(lv, 'output_field'): + r.append(f'{sflk}{"__" if sflk else ""}range') + + r += get_keys_lookups(lv.output_field.class_lookups, sflk) + + return r + + fields[f_str] = list( + set(get_keys_lookups(f.class_lookups, ''))) + + # Remove excluded fields + exclude = exclude or [] + + fields = [(f, lookups) + for f, lookups in fields.items() if f not in exclude] + + return OrderedDict(fields) + + @classmethod + def filter_for_field(cls, f, name, lookup_expr='exact'): + # Redefine método estático para ignorar filtro para + # fields que não possuam lookup_expr informado + + f, lookup_type = resolve_field(f, lookup_expr) + + default = { + 'field_name': name, + 'label': capfirst(f.verbose_name), + 'lookup_expr': lookup_expr + } + + filter_class, params = cls.filter_for_lookup( + f, lookup_type) + default.update(params) + if filter_class is not None: + return filter_class(**default) + return None diff --git a/sapl/api/forms.py b/sapl/api/forms.py index 7cb249ff3..e1b293fbc 100644 --- a/sapl/api/forms.py +++ b/sapl/api/forms.py @@ -1,65 +1,8 @@ -from django.db.models.fields.files import FileField -from django.template.defaultfilters import capfirst -import django_filters -from django_filters.filters import CharFilter, NumberFilter -from django_filters.rest_framework.filterset import FilterSet -from django_filters.utils import resolve_field -from sapl.sessao.models import SessaoPlenaria - - -class SaplFilterSetMixin(FilterSet): - - o = CharFilter(method='filter_o') - - class Meta: - fields = '__all__' - filter_overrides = { - FileField: { - 'filter_class': django_filters.CharFilter, - 'extra': lambda f: { - 'lookup_expr': 'exact', - }, - }, - } - - def filter_o(self, queryset, name, value): - try: - return queryset.order_by( - *map(str.strip, value.split(','))) - except: - return queryset - @classmethod - def filter_for_field(cls, f, name, lookup_expr='exact'): - # Redefine método estático para ignorar filtro para - # fields que não possuam lookup_expr informado - f, lookup_type = resolve_field(f, lookup_expr) - - default = { - 'field_name': name, - 'label': capfirst(f.verbose_name), - 'lookup_expr': lookup_expr - } - - filter_class, params = cls.filter_for_lookup( - f, lookup_type) - default.update(params) - if filter_class is not None: - return filter_class(**default) - return None +from sapl.api.core.filters import SaplFilterSetMixin +from sapl.sessao.models import SessaoPlenaria class SessaoPlenariaFilterSet(SaplFilterSetMixin): - year = NumberFilter(method='filter_year') - month = NumberFilter(method='filter_month') - class Meta(SaplFilterSetMixin.Meta): model = SessaoPlenaria - - def filter_year(self, queryset, name, value): - qs = queryset.filter(data_inicio__year=value) - return qs - - def filter_month(self, queryset, name, value): - qs = queryset.filter(data_inicio__month=value) - return qs