From 8f3c02d2927abdf8e60992d49fb1f6e7d9881868 Mon Sep 17 00:00:00 2001 From: Evarin Date: Mon, 14 Jan 2019 22:32:01 +0100 Subject: [PATCH 1/2] =?UTF-8?q?Possibilit=C3=A9=20de=20d=C3=A9velopper=20s?= =?UTF-8?q?ans=20ElasticSearch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 12 ++++-- avisstage/views_search.py | 83 ++++++++++++++++++++++++-------------- experiENS/settings_base.py | 8 ++-- experiENS/settings_dev.py | 9 +++++ 4 files changed, 75 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 096cc77..bee1ee7 100644 --- a/README.md +++ b/README.md @@ -41,9 +41,13 @@ Vous pouvez alors lancez le serveur de développement python manage.py runserver +C'est bon, vous pouvez développer sur ExpériENS ! + ## Configuration de la recherche -Il faut installer elasticsearch 5.*. C'est compliqué. Mais en suivant https://www.elastic.co/guide/en/elasticsearch/reference/5.4/deb.html ça va. +**Cette partie n'est pas obligatoire pour faire fonctionner un serveur de développement en local.** Elle n'est utile que si vous voulez toucher aux fonctionnalités de recherche. + +Il faut installer elasticsearch 5.*. C'est compliqué. Mais en suivant https://www.elastic.co/guide/en/elasticsearch/reference/5.4/deb.html c'est faisable. wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo apt-key add - sudo apt-get install apt-transport-https @@ -54,11 +58,13 @@ Il faut installer elasticsearch 5.*. C'est compliqué. Mais en suivant https://w sudo systemctl enable elasticsearch.service sudo systemctl start elasticsearch.service -Et puis, de retour dans le virtualenv python +Vous devez ensuite activer ElasticSearch dans vos paramètres locaux, en changeant `USE_ELASTICSEARCH = True` à la fin du fichier `experiENS/settings_dev.py`. + +Enfin, de retour dans la console et le virtualenv python, vous pouvez faire python manage.py search_index --rebuild -Si des erreurs s'affichent, il y a une cachuète dans le beurre. +Si des erreurs s'affichent, demandez de l'aide sur Merle ou par e-mail. ## Changer le CSS diff --git a/avisstage/views_search.py b/avisstage/views_search.py index 2690be6..300dc5b 100644 --- a/avisstage/views_search.py +++ b/avisstage/views_search.py @@ -4,6 +4,7 @@ from datetime import date from django import forms from django.contrib.auth.decorators import login_required +from django.conf import settings from django.core.cache import cache from django.core.paginator import Paginator from django.db.models import Q, Case, When @@ -13,7 +14,11 @@ from django.shortcuts import render, redirect, get_object_or_404 import json import logging -from .documents import StageDocument +USE_ELASTICSEARCH = getattr(settings, "USE_ELASTICSEARCH", True) + +if USE_ELASTICSEARCH: + from .documents import StageDocument + from .decorators import en_scolarite_required from .models import Stage from .statics import TYPE_LIEU_OPTIONS, TYPE_STAGE_OPTIONS, NIVEAU_SCOL_OPTIONS @@ -50,8 +55,6 @@ class SearchForm(forms.Form): def cherche(**kwargs): filtres = Q(public=True) - dsl = StageDocument.search() - use_dsl = False def field_relevant(field, test_string=True): @@ -59,35 +62,53 @@ def cherche(**kwargs): kwargs[field] is not None and \ ((not test_string) or kwargs[field].strip() != '') - # - # Recherche libre - # - - # Champ générique : recherche dans tous les champs - if field_relevant("generique"): - #print("Filtre generique", kwargs['generique']) - dsl = dsl.query( - "match", - _all={"query": kwargs["generique"], - "fuzziness": "auto"}) - use_dsl = True + if USE_ELASTICSEARCH: + dsl = StageDocument.search() - # Sujet -> Recherche dan les noms de sujets et les thématiques - if field_relevant("sujet"): - dsl = dsl.query("multi_match", - query = kwargs["sujet"], - fields = ['sujet^2', 'thematiques', 'matieres'], - fuzziness = "auto") - use_dsl = True + # + # Recherche libre AVEC ELASTICSEARCH + # - # Contexte -> Encadrants, structure, lieu - if field_relevant("contexte"): - dsl = dsl.query("multi_match", - query = kwargs["contexte"], - fields = ['encadrants', 'structure^2', - 'lieux.nom', 'lieux.pays', 'lieux.ville'], - fuzziness = "auto") - use_dsl = True + # Champ générique : recherche dans tous les champs + if field_relevant("generique"): + #print("Filtre generique", kwargs['generique']) + dsl = dsl.query( + "match", + _all={"query": kwargs["generique"], + "fuzziness": "auto"}) + use_dsl = True + + # Sujet -> Recherche dan les noms de sujets et les thématiques + if field_relevant("sujet"): + dsl = dsl.query("multi_match", + query = kwargs["sujet"], + fields = ['sujet^2', 'thematiques', 'matieres'], + fuzziness = "auto") + use_dsl = True + + # Contexte -> Encadrants, structure, lieu + if field_relevant("contexte"): + dsl = dsl.query("multi_match", + query = kwargs["contexte"], + fields = ['encadrants', 'structure^2', + 'lieux.nom', 'lieux.pays', 'lieux.ville'], + fuzziness = "auto") + use_dsl = True + + else: + # Sans ElasticSearch, on active quand même une approximation de + # recherche en base de données + if field_relevant("generique"): + generique = kwargs["generique"] + filtres |= Q(sujet__icontains=generique) + filtres |= Q(thematiques__name__icontains=generique) + filtres |= Q(matieres__nom__icontains=generique) + filtres |= Q(lieux__nom__icontains=generique) + + # Autres champs -> non fonctionnels + if field_relevant("sujet") or field_relevant("contexte"): + raise NotImplementedError( + "ElasticSearch doit être activé pour ce type de recherche") # # Filtres directs db @@ -115,7 +136,7 @@ def cherche(**kwargs): # Application - if use_dsl: + if USE_ELASTICSEARCH and use_dsl: filtres &= Q(id__in=[s.meta.id for s in dsl.scan()]) #print(filtres) diff --git a/experiENS/settings_base.py b/experiENS/settings_base.py index eb977ff..0c8e707 100644 --- a/experiENS/settings_base.py +++ b/experiENS/settings_base.py @@ -21,7 +21,7 @@ ALLOWED_HOSTS = [] # Application definition -INSTALLED_APPS = ( +INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -49,7 +49,7 @@ INSTALLED_APPS = ( 'taggit', 'taggit_autosuggest', 'avisstage' -) +] MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', @@ -61,6 +61,7 @@ MIDDLEWARE_CLASSES = ( 'django.middleware.clickjacking.XFrameOptionsMiddleware', ) + TEMPLATES = [ { 'BACKEND': 'django.template.backends.django.DjangoTemplates', @@ -83,6 +84,7 @@ TEMPLATES = [ }, ] + ROOT_URLCONF = 'experiENS.urls' WSGI_APPLICATION = 'experiENS.wsgi.application' @@ -94,7 +96,7 @@ WSGI_APPLICATION = 'experiENS.wsgi.application' # Internationalization # https://docs.djangoproject.com/en/1.7/topics/i18n/ -LANGUAGE_CODE = 'fr-fr' +LANGUAGE_CODE = 'fr' TIME_ZONE = 'Europe/Paris' diff --git a/experiENS/settings_dev.py b/experiENS/settings_dev.py index 4dee8e4..c9c9460 100644 --- a/experiENS/settings_dev.py +++ b/experiENS/settings_dev.py @@ -11,6 +11,7 @@ DATABASES = { } } +""" INSTALLED_APPS += ( 'debug_toolbar', ) @@ -18,6 +19,7 @@ INSTALLED_APPS += ( MIDDLEWARE_CLASSES = ( 'debug_toolbar.middleware.DebugToolbarMiddleware', ) + MIDDLEWARE_CLASSES +""" INTERNAL_IPS = ['127.0.0.1'] @@ -37,3 +39,10 @@ ELASTICSEARCH_DSL = { CLIPPER_LDAP_SERVER = 'ldaps://localhost:636' + +# Changer à True pour développer avec ES +USE_ELASTICSEARCH = False + +if not USE_ELASTICSEARCH: + INSTALLED_APPS.remove('django_elasticsearch_dsl') + From c0cbff507072e4a2bf33ff2680ef905584c0292c Mon Sep 17 00:00:00 2001 From: Evarin Date: Mon, 14 Jan 2019 22:37:01 +0100 Subject: [PATCH 2/2] Meilleure recherche sans elasticsearch --- avisstage/views_search.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/avisstage/views_search.py b/avisstage/views_search.py index 300dc5b..029fa71 100644 --- a/avisstage/views_search.py +++ b/avisstage/views_search.py @@ -100,10 +100,10 @@ def cherche(**kwargs): # recherche en base de données if field_relevant("generique"): generique = kwargs["generique"] - filtres |= Q(sujet__icontains=generique) - filtres |= Q(thematiques__name__icontains=generique) - filtres |= Q(matieres__nom__icontains=generique) - filtres |= Q(lieux__nom__icontains=generique) + filtres = (Q(sujet__icontains=generique) + | Q(thematiques__name__icontains=generique) + | Q(matieres__nom__icontains=generique) + | Q(lieux__nom__icontains=generique)) # Autres champs -> non fonctionnels if field_relevant("sujet") or field_relevant("contexte"):