Commit c3a2099e authored by okhin's avatar okhin 🚴

Merge branch 'search_update' into 'master'

Search update

See merge request !197
parents 56b5ee5e 9119a4d1
Pipeline #1057 passed with stage
in 11 minutes and 4 seconds
...@@ -36,3 +36,4 @@ data/ ...@@ -36,3 +36,4 @@ data/
# local setup # local setup
.memopol.alias .memopol.alias
whoosh_index/
...@@ -43,6 +43,9 @@ memopol migrate ...@@ -43,6 +43,9 @@ memopol migrate
memopol loaddata data_sample.json memopol loaddata data_sample.json
memopol refresh_scores memopol refresh_scores
# Build index for Whoosh
memopol rebuild_index
echo echo
echo "You're all set!" echo "You're all set!"
echo "To start the application run the following from the repository root ($REPOROOT):" echo "To start the application run the following from the repository root ($REPOROOT):"
......
...@@ -30,7 +30,10 @@ setup(name='political-memory', ...@@ -30,7 +30,10 @@ setup(name='political-memory',
'pytz', # Always use up-to-date TZ data 'pytz', # Always use up-to-date TZ data
'django-suit>=0.2,<0.3', 'django-suit>=0.2,<0.3',
'psycopg2>=2,<3', 'psycopg2>=2,<3',
'alabaster==0.7.10', 'django-haystack==2.6.0',
'pysolr==3.6.0',
'Whoosh==2.7.4',
'alabaster==0.7.10',
], ],
extras_require={ extras_require={
# Full version hardcode for testing dependencies so that # Full version hardcode for testing dependencies so that
......
...@@ -8,5 +8,6 @@ def main(): ...@@ -8,5 +8,6 @@ def main():
from django.core.management import execute_from_command_line from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv) execute_from_command_line(sys.argv)
if __name__ == "__main__": if __name__ == "__main__":
main() main()
from haystack import indexes
from representatives.models import Representative
class RepresentativeIndex(indexes.SearchIndex, indexes.Indexable):
text = indexes.EdgeNgramField(document=True, use_template=True)
slug = indexes.CharField(model_attr='slug', faceted=True)
first_name = indexes.CharField(model_attr='first_name', faceted=True)
last_name = indexes.CharField(model_attr='last_name', faceted=True)
full_name = indexes.EdgeNgramField(model_attr='full_name')
ascii_name = indexes.NgramField(model_attr='ascii_name')
def get_model(self):
return Representative
def index_queryset(self, using=None):
"""Used when the entire index for model is updated."""
return self.get_model().objects.all()
...@@ -58,6 +58,7 @@ INSTALLED_APPS = ( ...@@ -58,6 +58,7 @@ INSTALLED_APPS = (
'fontawesome', 'fontawesome',
'rest_framework', 'rest_framework',
'taggit', 'taggit',
'haystack',
# memopol apps # memopol apps
'core', 'core',
...@@ -341,3 +342,19 @@ if os.path.exists(RAVEN_FILE): ...@@ -341,3 +342,19 @@ if os.path.exists(RAVEN_FILE):
with open(RAVEN_FILE, 'r') as f: with open(RAVEN_FILE, 'r') as f:
RAVEN_CONFIG = {'dsn': f.read().strip()} RAVEN_CONFIG = {'dsn': f.read().strip()}
# Haystack with Solr config
if not DEBUG:
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.solr_backend.SolrEngine',
'URL': 'http://127.0.0.1:8080/solr',
},
}
else:
HAYSTACK_CONNECTIONS = {
'default': {
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
'PATH': os.path.join(os.path.dirname(__file__), 'whoosh_index'),
},
}
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css" /> <link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}" type="text/css" />
<link rel="stylesheet" href="{% static 'libs/flag-icon-css/css/flag-icon.min.css' %}" type="text/css" /> <link rel="stylesheet" href="{% static 'libs/flag-icon-css/css/flag-icon.min.css' %}" type="text/css" />
<link rel="stylesheet" href="{% static 'css/jquery-ui.min.css' %}" type="text/css" />
{% load compress %} {% load compress %}
{% compress css %} {% compress css %}
...@@ -28,6 +30,7 @@ ...@@ -28,6 +30,7 @@
{% endcompress %} {% endcompress %}
<script type="text/javascript" src="{% static 'libs/jquery/dist/jquery.min.js' %}"></script> <script type="text/javascript" src="{% static 'libs/jquery/dist/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/jquery-ui.min.js' %}"></script>
<script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script> <script type="text/javascript" src="{% static 'js/bootstrap.min.js' %}"></script>
{{ position_form.media }} {{ position_form.media }}
...@@ -86,5 +89,16 @@ ...@@ -86,5 +89,16 @@
$('[data-toggle="tooltip"]').tooltip() $('[data-toggle="tooltip"]').tooltip()
}) })
</script> </script>
<script>
$(function() {
$("#search").autocomplete({
source: "{% url 'representative-search-name-autocomplete' %}",
minLength: 2,
select: function(event, ui){
window.location.href = ui.item.link;
}
});
});
</script>
</body> </body>
</html> </html>
{{ object.id }}
{{ object.full_name }}
{{ object.slug }}$
{{ object.ascii_name}}
...@@ -26,6 +26,7 @@ from views.representative_detail_votes import RepresentativeDetailVotes ...@@ -26,6 +26,7 @@ from views.representative_detail_votes import RepresentativeDetailVotes
from views.representative_detail_mandates import RepresentativeDetailMandates from views.representative_detail_mandates import RepresentativeDetailMandates
from views.representative_detail_positions import RepresentativeDetailPositions from views.representative_detail_positions import RepresentativeDetailPositions
from views.representative_list import RepresentativeList from views.representative_list import RepresentativeList
from views.representative_search import search_autocomplete
from views.redirects import ( from views.redirects import (
RedirectRepresentativeDetail, RedirectRepresentativeDetail,
...@@ -241,5 +242,10 @@ urlpatterns = [ ...@@ -241,5 +242,10 @@ urlpatterns = [
ThemeDetailBase.as_view(), ThemeDetailBase.as_view(),
name='theme-none' name='theme-none'
), ),
url(
r'^representative/search/$',
search_autocomplete,
name="representative-search-name-autocomplete"
),
] + legacy_patterns ] + legacy_patterns
import unicodedata
def strip_accents(value):
return ''.join(
c for c in unicodedata.normalize('NFD', value)
if unicodedata.category(c) != 'Mn')
import json
from django.http import HttpResponse
from haystack.query import SearchQuerySet
from django.core.urlresolvers import reverse
from memopol.utils import strip_accents
def search_autocomplete(request):
if request.is_ajax():
q = strip_accents(request.GET.get('term', ''))
if q is not None:
json_results = []
sqs = SearchQuerySet().autocomplete(ascii_name=q)
for result in sqs:
result_json = {}
result_json['id'] = result.id
result_json['label'] = result.full_name
result_json['value'] = result.full_name
result_json['link'] = reverse(
'representative-detail', kwargs={'slug': result.slug})
json_results.append(result_json)
data = json.dumps(json_results)
else:
data = "Fail"
return HttpResponse(data, "application/json")
...@@ -8,4 +8,5 @@ class SettingAdmin(admin.ModelAdmin): ...@@ -8,4 +8,5 @@ class SettingAdmin(admin.ModelAdmin):
list_editable = ('key', 'value', 'comment') list_editable = ('key', 'value', 'comment')
list_filter = ('key',) list_filter = ('key',)
admin.site.register(Setting, SettingAdmin) admin.site.register(Setting, SettingAdmin)
...@@ -5,6 +5,7 @@ from datetime import datetime ...@@ -5,6 +5,7 @@ from datetime import datetime
from django.db import models from django.db import models
from django.utils.encoding import smart_unicode from django.utils.encoding import smart_unicode
from django.utils.functional import cached_property from django.utils.functional import cached_property
from memopol.utils import strip_accents
class TimeStampedModel(models.Model): class TimeStampedModel(models.Model):
...@@ -76,6 +77,9 @@ class Representative(TimeStampedModel): ...@@ -76,6 +77,9 @@ class Representative(TimeStampedModel):
genders = {0: 'N/A', 1: 'F', 2: 'M'} genders = {0: 'N/A', 1: 'F', 2: 'M'}
return genders[self.gender] return genders[self.gender]
def ascii_name(self):
return strip_accents(self.full_name).lower()
class Meta: class Meta:
ordering = ['last_name', 'first_name'] ordering = ['last_name', 'first_name']
......
...@@ -11,6 +11,7 @@ def publish_positions(modeladmin, request, queryset): ...@@ -11,6 +11,7 @@ def publish_positions(modeladmin, request, queryset):
"""Set published to True for the queryset""" """Set published to True for the queryset"""
queryset.update(published=True) queryset.update(published=True)
publish_positions.short_description = 'Publish selected positions' publish_positions.short_description = 'Publish selected positions'
...@@ -18,6 +19,7 @@ def unpublish_positions(modeladmin, request, queryset): ...@@ -18,6 +19,7 @@ def unpublish_positions(modeladmin, request, queryset):
"""Set published to False for the queryset""" """Set published to False for the queryset"""
queryset.update(published=False) queryset.update(published=False)
unpublish_positions.short_description = 'Unpublish selected positions' unpublish_positions.short_description = 'Unpublish selected positions'
......
...@@ -13,4 +13,5 @@ class RecommendationsAdmin(admin.ModelAdmin): ...@@ -13,4 +13,5 @@ class RecommendationsAdmin(admin.ModelAdmin):
'proposal__dossier__title') 'proposal__dossier__title')
form = RecommendationForm form = RecommendationForm
admin.site.register(Recommendation, RecommendationsAdmin) admin.site.register(Recommendation, RecommendationsAdmin)
...@@ -31,4 +31,6 @@ def skip_votes(sender, vote_data=None, **kwargs): ...@@ -31,4 +31,6 @@ def skip_votes(sender, vote_data=None, **kwargs):
if vote_data.get('epref', None) not in dossiers: if vote_data.get('epref', None) not in dossiers:
return False return False
vote_pre_import.connect(skip_votes) vote_pre_import.connect(skip_votes)
...@@ -56,6 +56,7 @@ class VoteAdmin(admin.ModelAdmin): ...@@ -56,6 +56,7 @@ class VoteAdmin(admin.ModelAdmin):
def proposal_reference(self, obj): def proposal_reference(self, obj):
return obj.proposal.reference return obj.proposal.reference
admin.site.register(Dossier, DossierAdmin) admin.site.register(Dossier, DossierAdmin)
admin.site.register(Document, DocumentAdmin) admin.site.register(Document, DocumentAdmin)
admin.site.register(Proposal, ProposalAdmin) admin.site.register(Proposal, ProposalAdmin)
......
...@@ -26,6 +26,7 @@ def _parse_date(date_str): ...@@ -26,6 +26,7 @@ def _parse_date(date_str):
date_parse(date_str), date_parse(date_str),
date_timezone('Europe/Brussels')) date_timezone('Europe/Brussels'))
JSON_URL = 'http://parltrack.euwiki.org/dumps/ep_votes.json.xz' JSON_URL = 'http://parltrack.euwiki.org/dumps/ep_votes.json.xz'
DESTINATION = join('/tmp', 'ep_votes.json') DESTINATION = join('/tmp', 'ep_votes.json')
RE_COMVOTE_REF = re.compile(r'&reference=([^&]+)') RE_COMVOTE_REF = re.compile(r'&reference=([^&]+)')
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment