mirror of https://github.com/interlegis/sapl.git
LeandroRoberto
8 years ago
15 changed files with 335 additions and 95 deletions
@ -0,0 +1,81 @@ |
|||||
|
from django.contrib.contenttypes.fields import GenericRel |
||||
|
from django.db.models import Q |
||||
|
from django_filters.filters import MethodFilter, ModelChoiceFilter |
||||
|
from rest_framework.filters import FilterSet |
||||
|
|
||||
|
from sapl.base.models import Autor, TipoAutor |
||||
|
from sapl.utils import SaplGenericRelation |
||||
|
|
||||
|
|
||||
|
def autores_models_generic_relations(): |
||||
|
models_of_generic_relations = list(map( |
||||
|
lambda x: x.related_model, |
||||
|
filter( |
||||
|
lambda obj: obj.is_relation and |
||||
|
hasattr(obj, 'field') and |
||||
|
isinstance(obj, GenericRel), |
||||
|
|
||||
|
Autor._meta.get_fields(include_hidden=True)) |
||||
|
)) |
||||
|
|
||||
|
models = list(map( |
||||
|
lambda x: (x, |
||||
|
list(filter( |
||||
|
lambda field: ( |
||||
|
isinstance( |
||||
|
field, SaplGenericRelation) and |
||||
|
field.related_model == Autor), |
||||
|
x._meta.get_fields(include_hidden=True)))), |
||||
|
models_of_generic_relations |
||||
|
)) |
||||
|
|
||||
|
return models |
||||
|
|
||||
|
|
||||
|
class AutorChoiceFilterSet(FilterSet): |
||||
|
q = MethodFilter() |
||||
|
tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all()) |
||||
|
|
||||
|
class Meta: |
||||
|
model = Autor |
||||
|
fields = ['q', |
||||
|
'tipo', |
||||
|
'nome', ] |
||||
|
|
||||
|
def filter_q(self, queryset, value): |
||||
|
|
||||
|
query = value.split(' ') |
||||
|
if query: |
||||
|
q = Q() |
||||
|
for qtext in query: |
||||
|
if not qtext: |
||||
|
continue |
||||
|
q_fs = Q(nome__icontains=qtext) |
||||
|
|
||||
|
order_by = [] |
||||
|
|
||||
|
for gr in autores_models_generic_relations(): |
||||
|
model = gr[0] |
||||
|
sgr = gr[1] |
||||
|
for item in sgr: |
||||
|
if item.related_model != Autor: |
||||
|
continue |
||||
|
flag_order_by = True |
||||
|
for field in item.fields_search: |
||||
|
if flag_order_by: |
||||
|
flag_order_by = False |
||||
|
order_by.append('%s__%s' % ( |
||||
|
item.related_query_name(), |
||||
|
field[0]) |
||||
|
) |
||||
|
q_fs = q_fs | Q(**{'%s__%s%s' % ( |
||||
|
item.related_query_name(), |
||||
|
field[0], |
||||
|
field[1]): qtext}) |
||||
|
|
||||
|
q = q & q_fs |
||||
|
|
||||
|
if q: |
||||
|
queryset = queryset.filter(q).order_by(*order_by) |
||||
|
|
||||
|
return queryset |
@ -1,9 +1,79 @@ |
|||||
|
from django.contrib.contenttypes.fields import GenericRel |
||||
from rest_framework import serializers |
from rest_framework import serializers |
||||
|
|
||||
|
from sapl.base.models import Autor |
||||
|
from sapl.utils import SaplGenericRelation |
||||
|
|
||||
|
|
||||
class ChoiceSerializer(serializers.Serializer): |
class ChoiceSerializer(serializers.Serializer): |
||||
pk = serializers.IntegerField() |
value = serializers.SerializerMethodField() |
||||
display = serializers.SerializerMethodField() |
text = serializers.SerializerMethodField() |
||||
|
|
||||
|
def get_text(self, obj): |
||||
|
return obj[1] |
||||
|
|
||||
|
def get_value(self, obj): |
||||
|
return obj[0] |
||||
|
|
||||
|
|
||||
|
class AutorChoiceSerializer(ChoiceSerializer): |
||||
|
|
||||
|
def get_text(self, obj): |
||||
|
return obj.nome |
||||
|
|
||||
|
def get_value(self, obj): |
||||
|
return obj.id |
||||
|
|
||||
|
class Meta: |
||||
|
model = Autor |
||||
|
fields = ['id', 'tipo', 'nome', 'object_id', 'autor_related', 'user'] |
||||
|
|
||||
|
# Models que apontaram uma GenericRelation com Autor |
||||
|
|
||||
|
|
||||
|
def autores_models_generic_relations(): |
||||
|
models_of_generic_relations = list(map( |
||||
|
lambda x: x.related_model, |
||||
|
filter( |
||||
|
lambda obj: obj.is_relation and |
||||
|
hasattr(obj, 'field') and |
||||
|
isinstance(obj, GenericRel), |
||||
|
|
||||
|
Autor._meta.get_fields(include_hidden=True)) |
||||
|
)) |
||||
|
|
||||
|
models = list(map( |
||||
|
lambda x: (x, |
||||
|
list(filter( |
||||
|
lambda field: ( |
||||
|
isinstance( |
||||
|
field, SaplGenericRelation) and |
||||
|
field.related_model == Autor), |
||||
|
x._meta.get_fields(include_hidden=True)))), |
||||
|
models_of_generic_relations |
||||
|
)) |
||||
|
|
||||
|
return models |
||||
|
|
||||
|
|
||||
|
class AutorObjectRelatedField(serializers.RelatedField): |
||||
|
|
||||
|
def to_representation(self, value): |
||||
|
|
||||
|
return str(value) |
||||
|
|
||||
|
for gr in autores_models_generic_relations(): |
||||
|
if isinstance(value, gr[0]): |
||||
|
verbose_name = gr[0]._meta.verbose_name |
||||
|
fields_search = gr[1][0].fields_search |
||||
|
|
||||
|
raise Exception(_('Erro na seleção de autor')) |
||||
|
|
||||
|
|
||||
|
class AutorSerializer(serializers.ModelSerializer): |
||||
|
|
||||
|
autor_related = AutorObjectRelatedField(read_only=True) |
||||
|
|
||||
def get_display(self, obj): |
class Meta: |
||||
return str(obj) |
model = Autor |
||||
|
fields = ['id', 'tipo', 'nome', 'object_id', 'autor_related', 'user'] |
||||
|
@ -1,18 +1,24 @@ |
|||||
from django.conf.urls import url |
from django.conf.urls import url, include |
||||
|
from sapl.api.views import AutorListView |
||||
from sapl.api.views import TipoAutorContentOfModelContentTypeView |
|
||||
|
|
||||
from .apps import AppConfig |
from .apps import AppConfig |
||||
|
|
||||
|
|
||||
app_name = AppConfig.name |
app_name = AppConfig.name |
||||
|
|
||||
|
|
||||
# router = DefaultRouter() |
# router = DefaultRouter() |
||||
|
|
||||
urlpatterns = [ |
# urlpatterns += router.urls |
||||
url(r'^autor/possiveis-pelo-tipo/(?P<pk>[0-9]+)$', |
|
||||
TipoAutorContentOfModelContentTypeView.as_view(), |
|
||||
name='autores_possiveis_pelo_tipo'), |
urlpatterns_api = [ |
||||
|
# url(r'^$', api_root), |
||||
|
url(r'^autor', |
||||
|
AutorListView.as_view(), |
||||
|
name='autor_list'), |
||||
] |
] |
||||
|
|
||||
# urlpatterns += router.urls |
urlpatterns = [ |
||||
|
url(r'^api/', include(urlpatterns_api)) |
||||
|
] |
||||
|
@ -1,50 +1,109 @@ |
|||||
|
|
||||
from django.db.models import Q |
from django.db.models import Q |
||||
from django.http import Http404 |
from django.http import Http404 |
||||
from rest_framework.generics import ListAPIView, get_object_or_404 |
from rest_framework.filters import DjangoFilterBackend |
||||
|
from rest_framework.generics import ListAPIView |
||||
from rest_framework.permissions import IsAuthenticated |
from rest_framework.permissions import IsAuthenticated |
||||
from rest_framework.viewsets import ModelViewSet |
|
||||
|
|
||||
from sapl.api.serializers import ChoiceSerializer |
from sapl.api.forms import AutorChoiceFilterSet |
||||
|
from sapl.api.serializers import ChoiceSerializer, AutorSerializer,\ |
||||
|
AutorChoiceSerializer |
||||
from sapl.base.models import Autor, TipoAutor |
from sapl.base.models import Autor, TipoAutor |
||||
from sapl.utils import SaplGenericRelation |
from sapl.utils import SaplGenericRelation |
||||
|
|
||||
|
|
||||
class TipoAutorContentOfModelContentTypeView(ListAPIView): |
class AutorListView(ListAPIView): |
||||
serializer_class = ChoiceSerializer |
""" |
||||
|
Listagem de Autores com filtro para autores já cadastrados |
||||
|
e/ou possíveis autores. |
||||
|
|
||||
|
- tipo - chave primária do Tipo de Autor a ser filtrado |
||||
|
- provaveis - variável sem relevância de valor, porém, sua presença |
||||
|
faz com que a AutorListView |
||||
|
mostre a lista de provaveis Autores armazenados segundo o |
||||
|
ContentType associado ao Tipo de Autor via relacionamento |
||||
|
genérico. |
||||
|
- q - busca textual no nome do Autor ou em fields_search |
||||
|
declarados no field SaplGenericRelation das GenericFks |
||||
|
|
||||
|
A busca textual acontece via django-filter se não |
||||
|
estiver presente a variável `provaveis`. Em caso |
||||
|
contrário, o django-filter é desativado e a busca é feita |
||||
|
no model do ContentType associado ao tipo. |
||||
|
""" |
||||
# FIXME aplicar permissão correta de usuário |
# FIXME aplicar permissão correta de usuário |
||||
permission_classes = (IsAuthenticated,) |
permission_classes = (IsAuthenticated,) |
||||
queryset = TipoAutor.objects.all() |
serializer_class = AutorSerializer |
||||
model = TipoAutor |
queryset = Autor.objects.all() |
||||
|
model = Autor |
||||
|
|
||||
|
def get(self, request, *args, **kwargs): |
||||
|
""" |
||||
|
desativa o django-filter se a busca for por provaveis autores |
||||
|
""" |
||||
|
provaveis = 'provaveis' in request.GET |
||||
|
self.filter_class = None if provaveis else AutorChoiceFilterSet |
||||
|
self.filter_backends = [] if provaveis else [DjangoFilterBackend] |
||||
|
self.serializer_class = ChoiceSerializer\ |
||||
|
if provaveis else AutorChoiceSerializer |
||||
|
|
||||
|
return ListAPIView.get(self, request, *args, **kwargs) |
||||
|
|
||||
def get_queryset(self): |
def get_queryset(self): |
||||
queryset = ModelViewSet.get_queryset(self) |
queryset = ListAPIView.get_queryset(self) |
||||
|
|
||||
if not self.kwargs['pk']: |
if self.filter_backends: |
||||
raise Http404() |
return queryset |
||||
|
|
||||
|
params = {'content_type__isnull': False} |
||||
|
|
||||
|
tipo = '' |
||||
|
try: |
||||
|
tipo = int(self.request.GET.get('tipo', '')) |
||||
|
if tipo: |
||||
|
params['id'] = tipo |
||||
|
except: |
||||
|
pass |
||||
|
|
||||
obj = get_object_or_404(queryset, pk=self.kwargs['pk']) |
tipos = TipoAutor.objects.filter(**params) |
||||
|
|
||||
if not obj.content_type: |
if not tipos.exists() and tipo: |
||||
raise Http404() |
raise Http404() |
||||
|
|
||||
q = self.request.GET.get('q', '').strip() |
r = [] |
||||
|
for tipo in tipos: |
||||
|
q = self.request.GET.get('q', '').strip() |
||||
|
|
||||
model_class = obj.content_type.model_class() |
model_class = tipo.content_type.model_class() |
||||
|
|
||||
fields = list(filter( |
fields = list(filter( |
||||
lambda field: isinstance(field, SaplGenericRelation) and |
lambda field: isinstance(field, SaplGenericRelation) and |
||||
field.related_model == Autor, |
field.related_model == Autor, |
||||
model_class._meta.get_fields(include_hidden=True))) |
model_class._meta.get_fields(include_hidden=True))) |
||||
|
|
||||
assert len(fields) == 1 |
# retirar assert |
||||
|
assert len(fields) == 1 |
||||
|
|
||||
fields_search = fields[0].fields_search |
qs = model_class.objects.all().order_by( |
||||
|
fields[0].fields_search[0][0]) |
||||
|
|
||||
if q: |
|
||||
q_filter = Q() |
q_filter = Q() |
||||
for fs in fields_search: |
if q: |
||||
q_filter |= Q(**{'%s__icontains' % fs: q}) |
for item in fields: |
||||
|
if item.related_model != Autor: |
||||
|
continue |
||||
|
q_fs = Q() |
||||
|
for field in item.fields_search: |
||||
|
q_fs = q_fs | Q(**{'%s%s' % ( |
||||
|
field[0], |
||||
|
field[1]): q}) |
||||
|
q_filter = q_filter & q_fs |
||||
|
|
||||
|
qs = qs.filter(q_filter).distinct( |
||||
|
fields[0].fields_search[0][0]) |
||||
|
|
||||
|
qs = qs.values_list('id', fields[0].fields_search[0][0]) |
||||
|
|
||||
return model_class.objects.filter(q_filter) |
r += list(qs) |
||||
else: |
r.sort(key=lambda x: x[1]) |
||||
return model_class.objects.all() |
return r |
||||
|
Loading…
Reference in new issue