Browse Source

Fix #809 full text search (#980)

* Inicia a pesquisa textual

* Melhora o front-end da pesquisa textual

* Bug fix

* Ajusta alguns detalhes e cria botão de acesso a pesquisa

* Adiciona signals para atualizar o index

* Inicia a pesquisa textual

* Melhora o front-end da pesquisa textual

* Bug fix

* Ajusta alguns detalhes e cria botão de acesso a pesquisa

* Adiciona signals para atualizar o index

* Insere ao README o comando de indexação

* Atualiza versão do Haystack

* Remove pacote haystack antigo
Coloca url de search no padrão
pull/978/head
eduardocalil 8 years ago
committed by Edward
parent
commit
fb0753d090
  1. 1
      .gitignore
  2. 3
      docs/instacao31.rst
  3. 3
      requirements/requirements.txt
  4. 58
      sapl/base/search_indexes.py
  5. 13
      sapl/base/templatetags/common_tags.py
  6. 2
      sapl/base/urls.py
  7. 3
      sapl/materia/apps.py
  8. 29
      sapl/materia/signals.py
  9. 11
      sapl/settings.py
  10. 4
      sapl/templates/materia/materialegislativa_filter.html
  11. 7
      sapl/templates/search/indexes/materia/documentoacessorio_text.txt
  12. 7
      sapl/templates/search/indexes/materia/materialegislativa_text.txt
  13. 95
      sapl/templates/search/search.html

1
.gitignore

@ -92,3 +92,4 @@ collected_static
bower
bower_components
media
whoosh/

3
docs/instacao31.rst

@ -187,6 +187,9 @@ Copie a chave que aparecerá, edite o arquivo .env e altere o valor do parâmetr
./manage.py collectstatic --noinput
* Preparar o ambiente para indexação de arquivos::
./manage.py rebuild_index
* Subir o servidor do django::
./manage.py runserver 0.0.0.0:8001

3
requirements/requirements.txt

@ -1,4 +1,5 @@
dj-database-url==0.4.1
django-haystack==2.6.0
django>=1.9,<1.10
# TODO O django-admin-bootstrapped 2.5.7 não inseriu a mudança que permite
# a compatibilidade com Django 1.9+. A linha abaixo será mudada quando uma
@ -25,7 +26,9 @@ python-decouple==3.0
pytz==2016.4
pyyaml==3.11
rtyaml==0.0.3
textract==1.5.0
unipath==1.1
python-magic==0.4.12
gunicorn==19.6.0
django-reversion==2.0.8
whoosh==2.7.4

58
sapl/base/search_indexes.py

@ -0,0 +1,58 @@
import textract
from haystack import indexes
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa
from django.template import Context, loader
class DocumentoAcessorioIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.CharField(document=True, use_template=True)
filename = 'arquivo'
model = DocumentoAcessorio
template_name = 'materia/documentoacessorio_text.txt'
def get_model(self):
return self.model
def index_queryset(self, using=None):
return self.get_model().objects.all()
def prepare(self, obj):
if not self.filename or not self.model or not self.template_name:
raise Exception
data = super(DocumentoAcessorioIndex, self).prepare(obj)
arquivo = getattr(obj, self.filename)
if arquivo:
try:
arquivo.open()
except OSError:
return self.prepared_data
extracted_data = textract.process(
arquivo.path).decode(
'utf-8').replace('\n', ' ')
extracted_data = extracted_data.replace('\t', ' ')
# Now we'll finally perform the template processing to render the
# text field with *all* of our metadata visible for templating:
t = loader.select_template((
'search/indexes/' + self.template_name, ))
data['text'] = t.render(Context({'object': obj,
'extracted': extracted_data}))
return data
return self.prepared_data
class MateriaLegislativaIndex(DocumentoAcessorioIndex):
text = indexes.CharField(document=True, use_template=True)
filename = 'texto_original'
model = MateriaLegislativa
template_name = 'materia/materialegislativa_text.txt'

13
sapl/base/templatetags/common_tags.py

@ -2,6 +2,7 @@ from compressor.utils import get_class
from django import template
from sapl.base.models import AppConfig
from sapl.materia.models import DocumentoAcessorio, MateriaLegislativa
from sapl.parlamentares.models import Filiacao
register = template.Library()
@ -124,7 +125,7 @@ def url(value):
@register.filter
def cronometro_to_seconds(value):
def cronometro_to_seconds(value):
if not AppConfig.attr('cronometro_' + value):
return 0
@ -137,3 +138,13 @@ def cronometro_to_seconds(value):
@register.filter
def to_list_pk(object_list):
return [o.pk for o in object_list]
@register.filter
def search_get_model(object):
if type(object) == MateriaLegislativa:
return 'm'
elif type(object) == DocumentoAcessorio:
return 'd'
return None

2
sapl/base/urls.py

@ -99,4 +99,6 @@ urlpatterns = [
name='login'),
url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout'),
url(r'^sistema/search/', include('haystack.urls')),
] + recuperar_senha

3
sapl/materia/apps.py

@ -6,3 +6,6 @@ class AppConfig(apps.AppConfig):
name = 'sapl.materia'
label = 'materia'
verbose_name = _('Matéria')
def ready(self):
from . import signals

29
sapl/materia/signals.py

@ -0,0 +1,29 @@
from django.db.models.signals import post_delete, post_save
from sapl.settings import PROJECT_DIR
from subprocess import PIPE, call
from threading import Thread
from .models import MateriaLegislativa, DocumentoAcessorio
class UpdateIndexCommand(Thread):
def run(self):
call([PROJECT_DIR.child('manage.py'), 'update_index'],
stdout=PIPE)
def save_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
def delete_texto(sender, instance, **kwargs):
update_index = UpdateIndexCommand()
update_index.start()
post_save.connect(save_texto, sender=MateriaLegislativa)
post_save.connect(save_texto, sender=DocumentoAcessorio)
post_delete.connect(delete_texto, sender=MateriaLegislativa)
post_delete.connect(delete_texto, sender=DocumentoAcessorio)

11
sapl/settings.py

@ -76,12 +76,23 @@ INSTALLED_APPS = (
'crispy_forms',
'easy_thumbnails',
'floppyforms',
'haystack',
'sass_processor',
'rest_framework',
'reversion',
'whoosh',
) + SAPL_APPS
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': PROJECT_DIR.child('whoosh'),
},
}
if DEBUG:
INSTALLED_APPS += ('debug_toolbar', 'rest_framework_docs',)

4
sapl/templates/materia/materialegislativa_filter.html

@ -4,6 +4,10 @@
{% block actions %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-default">
Pesquisa Textual
</a>
{% if perms.materia %}
<a href="{% url 'sapl.materia:materialegislativa_create' %}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Matéria Legislativa {% endblocktrans %}

7
sapl/templates/search/indexes/materia/documentoacessorio_text.txt

@ -0,0 +1,7 @@
{% for k, v in extracted.metadata.items %}
{% for val in v %}
{{ k }}: {{ val|safe }}
{% endfor %}
{% endfor %}
{{ extracted|striptags|safe }}

7
sapl/templates/search/indexes/materia/materialegislativa_text.txt

@ -0,0 +1,7 @@
{% for k, v in extracted.metadata.items %}
{% for val in v %}
{{ k }}: {{ val|safe }}
{% endfor %}
{% endfor %}
{{ extracted|striptags|safe }}

95
sapl/templates/search/search.html

@ -0,0 +1,95 @@
{% extends 'crud/form.html' %}
{% load crispy_forms_tags %}
{% load common_tags %}
{% block base_content %}
<h1><legend>Pesquisa Textual</legend></h1>
</br>
<form method="get" action=".">
<div class="row container-detail clearfix">
<div class="row-fluid">
<div class="col-md-8">
{{ form.q|as_crispy_field }}
</div>
</div>
<div class="row-fluid">
<div class="col-md-8">
</br>
<h4> Em quais tipos de documento deseja pesquisar?</h4>
</div>
</div>
<div class="row-fluid">
<div class="col-md-8">
{{ form.models }}
</div>
</div>
<div class="row-fluid">
<div class="col-md-12">
<input class="btn btn-primary pull-right" type="submit" value="Pesquisar">
</div>
</div>
</div>
</br>
{% if query %}
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
{% for result in page.object_list %}
<tr>
<td>
{% if result.object|search_get_model == 'm' %}
<p>
<strong>Matéria Legislativa: </strong> <a href="{% url 'sapl.materia:materialegislativa_detail' result.object.pk %}">{{ result.object }}</a></br>
{% if result.object.texto_original %}
<strong>Texto Original:</strong> <a href="{{result.object.texto_original.url}}"> Clique aqui </a></br>
{% else %}
<strong>O texto desta matéria foi removido recentemente. Em breve ela sairá desta listagem.</strong></br>
{% endif %}
</p>
{% elif result.object|search_get_model == 'd' %}
<p>
<strong> Documento Acessório: </strong><a href="{% url 'sapl.materia:documentoacessorio_detail' result.object.pk %}">{{ result.object }}</a></br>
{% if result.object.arquivo %}
<strong>Texto Original:</strong> <a href="{{result.object.arquivo.url}}"> Clique aqui </a></br>
{% else %}
<strong>O texto deste documento foi removido recentemente. Em breve ele sairá desta listagem.</strong></br>
{% endif %}
</p>
{% endif %}
</td>
</tr>
{% empty %}
<h3> Nenhum texto encontrado! </h3>
<tr>
<td>
</td>
</tr>
{% endfor %}
</table>
{% if page.has_previous or page.has_next %}
<div>
{% if page.has_previous %}<a href="?q={{ query }}&amp;page={{ page.previous_page_number }}">{% endif %}&laquo; Previous{% if page.has_previous %}</a>{% endif %}
|
{% if page.has_next %}<a href="?q={{ query }}&amp;page={{ page.next_page_number }}">{% endif %}Next &raquo;{% if page.has_next %}</a>{% endif %}
</div>
{% endif %}
{% else %}
{# Show some example queries to run, maybe query syntax, something else? #}
{% endif %}
</form>
{% endblock %}
Loading…
Cancel
Save