From e66142a2d699bf49bb54a23beef1ba0ada958d30 Mon Sep 17 00:00:00 2001 From: Edward <9326037+edwardoliveira@users.noreply.github.com> Date: Wed, 11 Mar 2020 15:58:20 -0300 Subject: [PATCH] =?UTF-8?q?Refatora=20num=20mat=C3=A9rias=20por=20tipo=20(?= =?UTF-8?q?#3121)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refatora num matérias por tipo * Adaptação p/ caso que utiliza MateriaEmTramitacao * Update sapl/utils.py Co-Authored-By: Edward <9326037+edwardoliveira@users.noreply.github.com> * Update sapl/utils.py Co-Authored-By: Edward <9326037+edwardoliveira@users.noreply.github.com> * Update utils.py Co-authored-by: João Rodrigues Co-authored-by: Edward <9326037+edwardoliveira@users.noreply.github.com> --- requirements/requirements.txt | 2 +- sapl/base/views.py | 34 +++++++++------------------------- sapl/utils.py | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 4dd300be0..eb203382f 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -27,7 +27,7 @@ unipath==1.1 WeasyPrint==51 Pillow==6.2.0 gunicorn==19.9.0 - +more-itertools==8.2.0 pysolr==3.6.0 pyoai==2.5.0 diff --git a/sapl/base/views.py b/sapl/base/views.py index 0d11c5692..305518ae0 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -56,9 +56,9 @@ from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, Protocol TipoDocumentoAdministrativo) from sapl.sessao.models import (Bancada, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoSessaoPlenaria) -from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, +from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured, parlamentares_ativos, - SEPARADOR_HASH_PROPOSICAO, show_results_filter_set) + SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, num_materias_por_tipo) from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, @@ -761,13 +761,7 @@ class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView): data['queryset'] = qs - qtdes = { tipo:0 for tipo in TipoMateriaLegislativa.objects.all() } - for i in qs: - qtdes[i.materia.tipo] += 1 - - # remove as entradas de valor igual a zero - qtdes = {k:v for k,v in qtdes.items() if v > 0} - self.total_resultados_tipos = qtdes + self.total_resultados_tipos = num_materias_por_tipo(qs, "materia__tipo") return data @@ -894,13 +888,8 @@ class RelatorioMateriasPorAnoAutorTipoView(RelatorioMixin, FilterView): context['title'] = _('Matérias por Ano, Autor e Tipo') if not self.filterset.form.is_valid(): return context - qtdes = {} - for tipo in TipoMateriaLegislativa.objects.all(): - qs = context['object_list'] - qtde = len(qs.filter(tipo_id=tipo.id)) - if qtde > 0: - qtdes[tipo] = qtde - context['qtdes'] = qtdes + qs = context['object_list'] + context['qtdes'] = num_materias_por_tipo(qs) qr = self.request.GET.copy() context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' @@ -936,13 +925,8 @@ class RelatorioMateriasPorAutorView(RelatorioMixin, FilterView): if not self.filterset.form.is_valid(): return context - qtdes = {} - for tipo in TipoMateriaLegislativa.objects.all(): - qs = context['object_list'] - qtde = len(qs.filter(tipo_id=tipo.id)) - if qtde > 0: - qtdes[tipo] = qtde - context['qtdes'] = qtdes + qs = context['object_list'] + context['qtdes'] = num_materias_por_tipo(qs) qr = self.request.GET.copy() context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' @@ -960,8 +944,8 @@ class RelatorioMateriasPorAutorView(RelatorioMixin, FilterView): else: context['autor'] = '' context['periodo'] = ( - self.request.GET['data_apresentacao_0'] + - ' - ' + self.request.GET['data_apresentacao_1']) + self.request.GET['data_apresentacao_0'] + + ' - ' + self.request.GET['data_apresentacao_1']) return context diff --git a/sapl/utils.py b/sapl/utils.py index 5a52f938c..ded879806 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -1,3 +1,5 @@ +from itertools import groupby + import django_filters import hashlib import logging @@ -6,7 +8,7 @@ import os import re import unicodedata -from crispy_forms.layout import Button, HTML +from crispy_forms.layout import Button, HTML from easy_thumbnails import source_generators from floppyforms import ClearableFileInput from functools import wraps @@ -44,6 +46,32 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE SEPARADOR_HASH_PROPOSICAO = 'K' +def num_materias_por_tipo(qs, attr_tipo='tipo'): + """ + :argument um QuerySet em MateriaLegislativa + :return um dict com o mapeamento {tipo: }, + se não existir o matéria para o tipo informado então não + haverá entrada no dicionário. + """ + qtdes = {} + + if attr_tipo == 'tipo': + def sort_function(m): return m.tipo + else: + def sort_function(m): return m.materia.tipo + + # select_related eh importante por questoes de desempenho, pois caso + # contrario ele realizara uma consulta ao banco para cada iteracao, + # na key do groupby (uma alternativa é só usar tipo_id, na chave). + qs2 = qs.select_related(attr_tipo).order_by(attr_tipo+'_id') + + for key, values in groupby(qs2, key=sort_function): + # poderia usar qtdes[key] = len(list(values)) aqui, mas + # desse modo economiza memória RAM + qtdes[key] = sum(1 for x in values) + return qtdes + + def validar_arquivo(arquivo, nome_campo): if len(arquivo.name) > 200: raise ValidationError( @@ -1032,4 +1060,4 @@ class OverwriteStorage(FileSystemStorage): def get_available_name(self, name, max_length=None): if self.exists(name): os.remove(os.path.join(settings.MEDIA_ROOT, name)) - return name \ No newline at end of file + return name