Browse Source

Refatora api para incluir filtro via lookups passados por queryparams (#3445)

* isola filtro mixin para adição de lookups

* refatora api para filtrar com lookups
pull/3446/head
Leandro Roberto Silva 3 years ago
committed by GitHub
parent
commit
9ae1f401ae
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      sapl/api/core/__init__.py
  2. 105
      sapl/api/core/filters.py
  3. 61
      sapl/api/forms.py

6
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)

105
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

61
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

Loading…
Cancel
Save