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 sapl.base.models import Autor |
|||
from sapl.utils import SaplGenericRelation |
|||
|
|||
|
|||
class ChoiceSerializer(serializers.Serializer): |
|||
pk = serializers.IntegerField() |
|||
display = serializers.SerializerMethodField() |
|||
value = 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): |
|||
return str(obj) |
|||
class Meta: |
|||
model = Autor |
|||
fields = ['id', 'tipo', 'nome', 'object_id', 'autor_related', 'user'] |
|||
|
@ -1,18 +1,24 @@ |
|||
from django.conf.urls import url |
|||
|
|||
from sapl.api.views import TipoAutorContentOfModelContentTypeView |
|||
from django.conf.urls import url, include |
|||
from sapl.api.views import AutorListView |
|||
|
|||
from .apps import AppConfig |
|||
|
|||
|
|||
app_name = AppConfig.name |
|||
|
|||
|
|||
# router = DefaultRouter() |
|||
|
|||
urlpatterns = [ |
|||
url(r'^autor/possiveis-pelo-tipo/(?P<pk>[0-9]+)$', |
|||
TipoAutorContentOfModelContentTypeView.as_view(), |
|||
name='autores_possiveis_pelo_tipo'), |
|||
# urlpatterns += router.urls |
|||
|
|||
|
|||
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.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.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.utils import SaplGenericRelation |
|||
|
|||
|
|||
class TipoAutorContentOfModelContentTypeView(ListAPIView): |
|||
serializer_class = ChoiceSerializer |
|||
class AutorListView(ListAPIView): |
|||
""" |
|||
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 |
|||
permission_classes = (IsAuthenticated,) |
|||
queryset = TipoAutor.objects.all() |
|||
model = TipoAutor |
|||
serializer_class = AutorSerializer |
|||
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): |
|||
queryset = ModelViewSet.get_queryset(self) |
|||
queryset = ListAPIView.get_queryset(self) |
|||
|
|||
if not self.kwargs['pk']: |
|||
raise Http404() |
|||
if self.filter_backends: |
|||
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() |
|||
|
|||
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( |
|||
lambda field: isinstance(field, SaplGenericRelation) and |
|||
field.related_model == Autor, |
|||
model_class._meta.get_fields(include_hidden=True))) |
|||
fields = list(filter( |
|||
lambda field: isinstance(field, SaplGenericRelation) and |
|||
field.related_model == Autor, |
|||
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() |
|||
for fs in fields_search: |
|||
q_filter |= Q(**{'%s__icontains' % fs: q}) |
|||
if 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) |
|||
else: |
|||
return model_class.objects.all() |
|||
r += list(qs) |
|||
r.sort(key=lambda x: x[1]) |
|||
return r |
|||
|
Loading…
Reference in new issue