pays.queryset = pays.queryset.filter(region=region)
def get_query_set(self):
- qs = Chercheur.objects.all()
+ chercheurs = Chercheur.objects
if self.is_valid():
+ q = self.cleaned_data["q"]
+ if q:
+ chercheurs = chercheurs.search(q)
nom = self.cleaned_data['nom']
if nom:
- qs = qs.search_nom(nom)
- domaine = self.cleaned_data["domaine"]
- if domaine:
- qs = qs.filter(groupes=domaine)
+ chercheurs = chercheurs.add_to_query('@(nom,prenom) ' + nom)
groupe_recherche = self.cleaned_data['groupe_recherche']
if groupe_recherche:
- for word in groupe_recherche.split():
- qs = qs.filter(groupe_recherche__icontains=word)
- q = self.cleaned_data["q"]
- if q:
- qs = qs.search(q)
- statut = self.cleaned_data["statut"]
- if statut:
- if statut == "expert":
- qs = qs.exclude(expertises=None)
- else:
- qs = qs.filter(statut=statut)
+ chercheurs = chercheurs.add_to_query('@groupe_recherche ' + groupe_recherche)
discipline = self.cleaned_data['discipline']
if discipline:
- qs = qs.filter_discipline(discipline)
+ chercheurs = chercheurs.filter_discipline(discipline)
region = self.cleaned_data['region']
if region:
- qs = qs.filter_region(region)
+ chercheurs = chercheurs.filter_region(region)
+ statut = self.cleaned_data["statut"]
+ if statut:
+ if statut == "expert":
+ chercheurs = chercheurs.filter_expert()
+ else:
+ chercheurs = chercheurs.filter_statut(statut)
+ domaine = self.cleaned_data["domaine"]
+ if domaine:
+ chercheurs = chercheurs.filter_groupe(domaine)
pays = self.cleaned_data["pays"]
if pays:
- qs = qs.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
+ chercheurs = chercheurs.filter_pays(pays)
nord_sud = self.cleaned_data['nord_sud']
if nord_sud:
- qs = qs.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud))
- return qs
+ chercheurs = chercheurs.filter_nord_sud(nord_sud)
+ return chercheurs.all()
class SendPasswordForm(forms.Form):
email = forms.EmailField(required=True, label="Adresse électronique")
# -*- encoding: utf-8 -*-
import hashlib
+from datamaster_modeles.models import *
from django.db import models
from django.db.models import Q
from django.utils.encoding import smart_str
-from datamaster_modeles.models import *
-#from auf_references_modeles.models import Thematique
-from savoirs.models import Discipline, RandomQuerySetMixin
+from djangosphinx.models import SphinxSearch
+from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySet
GENRE_CHOICES = (('m', 'Homme'), ('f', 'Femme'))
class Personne(models.Model):
def get_new_password_code(self):
return hashlib.md5(smart_str(u.courriel+u.encrypted_password)).hexdigest()[0:6]
-class ChercheurManager(models.Manager):
+class ChercheurQuerySet(SEPQuerySet):
+
+ def filter_groupe(self, groupe):
+ return self.filter(groupes=groupe)
+
+ def filter_pays(self, pays):
+ return self.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
+
+ def filter_region(self, region):
+ return self.filter(Q(etablissement__pays__region=region) | Q(etablissement_autre_pays__region=region))
+
+ def filter_nord_sud(self, nord_sud):
+ return self.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud))
+
+ def filter_statut(self, statut):
+ return self.filter(statut=statut)
+
+ def filter_expert(self):
+ return self.exclude(expertises=None)
+
+class ChercheurSphinxQuerySet(SEPSphinxQuerySet):
+
+ def __init__(self, model=None):
+ return SEPSphinxQuerySet.__init__(self, model=model, index='chercheurs',
+ weights=dict(nom=2, prenom=2))
+
+ def filter_region(self, region):
+ return self.filter(region_id=region.id)
+
+ def filter_groupe(self, groupe):
+ return self.filter(groupe_ids=groupe.id)
+
+ def filter_pays(self, pays):
+ return self.filter(pays_id=pays.id)
+
+ NORD_SUD_CODES = {'Nord': 1, 'Sud': 2}
+ def filter_nord_sud(self, nord_sud):
+ return self.filter(nord_sud=self.NORD_SUD_CODES[nord_sud])
+
+ STATUT_CODES = {'enseignant': 1, 'etudiant': 2, 'independant': 3}
+ def filter_statut(self, statut):
+ return self.filter(statut=self.STATUT_CODES[statut])
+
+ def filter_expert(self):
+ return self.filter(expert=1)
+
+class ChercheurManager(SEPManager):
def get_query_set(self):
return ChercheurQuerySet(self.model)
- def search(self, text):
- return self.get_query_set().search(text)
-
- def search_nom(self, nom):
- return self.get_query_set().search_nom(nom)
+ def get_sphinx_query_set(self):
+ return ChercheurSphinxQuerySet(self.model).order_by('-date_modification')
def filter_region(self, region):
+ """Le filtrage de chercheurs par région n'est pas une recherche texte."""
return self.get_query_set().filter_region(region)
- def filter_discipline(self, discipline):
- return self.get_query_set().filter_discipline(discipline)
-
-class ChercheurQuerySet(models.query.QuerySet, RandomQuerySetMixin):
-
- def search(self, text):
- q = None
- for word in text.split():
- matching_pays = list(Pays.objects.filter(Q(nom__icontains=word) | Q(region__nom__icontains=word)).values_list('pk', flat=True))
- matching_etablissements = list(Etablissement.objects.filter(Q(nom__icontains=word) | Q(pays__in=matching_pays)).values_list('pk', flat=True))
- matching_publications = list(Publication.objects.filter(titre__icontains=word).values_list('pk', flat=True))
- matching_groupes = list(Groupe.objects.filter(nom__icontains=word).values_list('pk', flat=True))
- matching_disciplines = list(Discipline.objects.filter(nom__icontains=word).values_list('pk', flat=True))
- part = (Q(personne__nom__icontains=word) |
- Q(personne__prenom__icontains=word) |
- Q(theme_recherche__icontains=word) |
- Q(etablissement__in=matching_etablissements) |
- Q(etablissement_autre_nom__icontains=word) |
- Q(etablissement_autre_pays__in=matching_pays) |
- Q(discipline__in=matching_disciplines) |
- Q(groupe_recherche__icontains=word) |
- Q(publication1__in=matching_publications) |
- Q(publication2__in=matching_publications) |
- Q(publication3__in=matching_publications) |
- Q(publication4__in=matching_publications) |
- Q(these__in=matching_publications) |
- Q(groupes__in=matching_groupes) |
- Q(expertises__nom__icontains=word) |
- Q(mots_cles__icontains=word) |
- Q(membre_association_francophone_details__icontains=word) |
- Q(membre_reseau_institutionnel_details__icontains=word)
- )
- if q is None:
- q = part
- else:
- q = q & part
- return self.filter(q).distinct() if q is not None else self
-
- def search_nom(self, nom):
- q = None
- for word in nom.split():
- part = Q(personne__nom__icontains=word) | Q(personne__prenom__icontains=word)
- if q is None:
- q = part
- else:
- q = q & part
- return self.filter(q) if q is not None else self
-
- def filter_discipline(self, discipline):
- """Ne conserve que les chercheurs dans la discipline donnée.
-
- Si ``disicipline`` est None, ce filtre n'a aucun effet."""
- if discipline is None:
- return self
- if not isinstance(discipline, Discipline):
- discipline = Discipline.objects.get(pk=discipline)
- return self.filter(Q(discipline=discipline) |
- Q(theme_recherche__icontains=discipline.nom) |
- Q(groupe_recherche__icontains=discipline.nom) |
- Q(publication1__titre__icontains=discipline.nom) |
- Q(publication2__titre__icontains=discipline.nom) |
- Q(publication3__titre__icontains=discipline.nom) |
- Q(publication4__titre__icontains=discipline.nom) |
- Q(these__titre__icontains=discipline.nom) |
- Q(groupes__nom__icontains=discipline.nom) |
- Q(expertises__nom__icontains=discipline.nom) |
- Q(mots_cles__icontains=discipline.nom) |
- Q(membre_instance_auf_details__icontains=discipline.nom) |
- Q(membre_association_francophone_details__icontains=discipline.nom) |
- Q(expert_oif_details__icontains=discipline.nom) |
- Q(membre_reseau_institutionnel_details__icontains=discipline.nom)).distinct()
+ def filter_groupe(self, groupe):
+ return self.get_query_set().filter_groupe(groupe)
- def filter_region(self, region):
- """Ne conserve que les évènements dans la région donnée.
-
- Si ``region`` est None, ce filtre n'a aucun effet."""
- if region is None:
- return self
- return self.filter(Q(etablissement__pays__region=region) |
- Q(etablissement_autre_pays__region=region))
+ def filter_pays(self, pays):
+ return self.get_query_set().filter_pays(pays)
+
+ def filter_nord_sud(self, nord_sud):
+ return self.get_query_set().filter_nord_sud(nord_sud)
+
+ def filter_statut(self, statut):
+ return self.get_query_set().filter_statut(statut)
+
+ def filter_expert(self):
+ return self.get_query_set().filter_expert()
STATUT_CHOICES = (('enseignant', 'Enseignant-chercheur dans un établissement'), ('etudiant', 'Étudiant-chercheur doctorant'), ('independant', 'Chercheur indépendant docteur'))
class Chercheur(models.Model):
# Manager
objects = ChercheurManager()
+ all_objects = models.Manager()
def __unicode__(self):
return u"%s %s" % (self.personne.nom.upper(), self.personne.prenom.title())
from django.core.urlresolvers import reverse as url
from django.db import models
+from django.db.models.query import QuerySet
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from django.utils.encoding import smart_unicode, iri_to_uri
from django.http import HttpResponseRedirect
-
-from models import SourceActualite, Actualite, Discipline, Evenement, Record, ListSet, HarvestLog, Profile
from savoirs.globals import META
+from savoirs.models import SourceActualite, Actualite, Discipline, Evenement, Record, ListSet, HarvestLog, Profile
admin.site.register(SourceActualite)
form.base_fields[field_name].required = False
return form
+class RecordAdminQuerySet(QuerySet):
+
+ def filter(self, *args, **kwargs):
+ """Gère des filtres supplémentaires pour l'admin.
+
+ C'est la seule façon que j'ai trouvée de contourner les mécanismes
+ de recherche de l'admin."""
+ search = kwargs.pop('admin_search', None)
+ search_titre = kwargs.pop('admin_search_titre', None)
+ search_sujet = kwargs.pop('admin_search_sujet', None)
+ search_description = kwargs.pop('admin_search_description', None)
+ search_auteur = kwargs.pop('admin_search_auteur', None)
+
+ if search:
+ qs = self
+ search_all = not (search_titre or search_description or search_sujet or search_auteur)
+ fields = []
+ if search_titre or search_all:
+ fields += ['title', 'alt_title']
+ if search_description or search_all:
+ fields += ['description', 'abstract']
+ if search_sujet or search_all:
+ fields += ['subject']
+ if search_auteur or search_all:
+ fields += ['creator', 'contributor']
+
+ for bit in search.split():
+ or_queries = [Q(**{field + '__icontains': bit}) for field in fields]
+ qs = qs.filter(reduce(operator.or_, or_queries))
+
+ if args or kwargs:
+ qs = super(RecordAdminQuerySet, qs).filter(*args, **kwargs)
+ return qs
+ else:
+ return super(RecordAdminQuerySet, self).filter(*args, **kwargs)
class RecordAdmin(ReadOnlyAdminFields, admin.ModelAdmin):
fields = ['server', 'title', 'creator', 'description', 'modified',
self.readonly_fields.append('listsets')
super(RecordAdmin, self).__init__(*args, **kwargs)
- # Recherche par mots-clés
+ def queryset(self):
+ return RecordAdminQuerySet(Record)
# Présentation de l'information
selected = request.POST.getlist(admin.ACTION_CHECKBOX_NAME)
return HttpResponseRedirect(url('assigner_disciplines', kwargs=dict(app_name='savoirs', model_name='record')) + '?ids=' + ','.join(selected))
assigner_disciplines.short_description = u'Assigner des disciplines'
-
admin.site.register(Record, RecordAdmin)
class ListSetAdmin(ReadOnlyAdminFields, admin.ModelAdmin):
def get_query_set(self):
"""Retourne l'ensemble des ressources qui correspondent aux valeurs
entrées dans le formulaire."""
- records = Record.objects.validated()
+ records = Record.objects
if self.is_valid():
- query = self.cleaned_data['q']
- if query:
- records = records.search(query)
+ q = self.cleaned_data['q']
+ if q:
+ records = records.search(q)
auteur = self.cleaned_data['auteur']
if auteur:
- records = records.search_auteur(auteur)
+ records = records.add_to_query('@(creator,contributor) ' + auteur)
titre = self.cleaned_data['titre']
if titre:
- records = records.search_titre(titre)
+ records = records.add_to_query('@title ' + titre)
sujet = self.cleaned_data['sujet']
if sujet:
- records = records.search_sujet(sujet)
+ records = records.add_to_query('@subject ' + sujet)
publisher = self.cleaned_data['publisher']
if publisher:
- for word in publisher.split():
- records = records.filter(publisher__icontains=word)
+ records = records.add_to_query('@publisher ' + publisher)
discipline = self.cleaned_data['discipline']
if discipline:
records = records.filter_discipline(discipline)
region = self.cleaned_data['region']
if region:
records = records.filter_region(region)
- return records
-
- def get_search_regexp(self):
- """Retourne une expression régulière compilée qui peut servir à
- chercher les mot-clés recherchés dans un texte."""
- if self.is_valid():
- return build_search_regexp(self.cleaned_data['q'])
+ return records.all()
class ActualiteSearchForm(forms.Form):
"""Formulaire de recherche pour les actualités."""
def get_query_set(self):
"""Retourne l'ensemble des actualités qui correspondent aux valeurs
entrées dans le formulaire."""
- actualites = Actualite.objects.filter(visible=True)
+ actualites = Actualite.objects
if self.is_valid():
- query = self.cleaned_data['q']
- if query:
- actualites = actualites.search(query)
- date_min = self.cleaned_data['date_min']
- if date_min:
- actualites = actualites.filter(date__gte=date_min)
- date_max = self.cleaned_data['date_max']
- if date_max:
- actualites = actualites.filter(date__lte=date_max)
+ q = self.cleaned_data['q']
+ if q:
+ actualites = actualites.search(q)
discipline = self.cleaned_data['discipline']
if discipline:
actualites = actualites.filter_discipline(discipline)
region = self.cleaned_data['region']
if region:
actualites = actualites.filter_region(region)
- return actualites
+ date_min = self.cleaned_data['date_min']
+ if date_min:
+ actualites = actualites.filter_date(min=date_min)
+ date_max = self.cleaned_data['date_max']
+ if date_max:
+ actualites = actualites.filter_date(max=date_max)
+ return actualites.all()
- def get_search_regexp(self):
- """Retourne une expression régulière compilée qui peut servir à
- chercher les mot-clés recherchés dans un texte."""
- if self.is_valid():
- return build_search_regexp(self.cleaned_data['q'])
-
class EvenementSearchForm(forms.Form):
"""Formulaire de recherche pour les évènements."""
def get_query_set(self):
"""Retourne l'ensemble des évènements qui correspondent aux valeurs
entrées dans le formulaire."""
- evenements = Evenement.objects.filter(approuve=True)
+ evenements = Evenement.objects
if self.is_valid():
query = self.cleaned_data['q']
if query:
evenements = evenements.search(query)
titre = self.cleaned_data['titre']
if titre:
- evenements = evenements.search_titre(titre)
- type = self.cleaned_data['type']
- if type:
- evenements = evenements.filter(type=type)
- date_min = self.cleaned_data['date_min']
- if date_min:
- evenements = evenements.filter(debut__gte=date_min)
- date_max = self.cleaned_data['date_max']
- if date_max:
- evenements = evenements.filter(debut__lte=date_max)
+ evenements = evenements.add_to_query('@titre ' + titre)
discipline = self.cleaned_data['discipline']
if discipline:
evenements = evenements.filter_discipline(discipline)
region = self.cleaned_data['region']
if region:
evenements = evenements.filter_region(region)
- return evenements
-
- def get_search_regexp(self):
- """Retourne une expression régulière compilée qui peut servir à
- chercher les mot-clés recherchés dans un texte."""
- if self.is_valid():
- return build_search_regexp(self.cleaned_data['q'])
+ type = self.cleaned_data['type']
+ if type:
+ evenements = evenements.filter_type(type)
+ date_min = self.cleaned_data['date_min']
+ if date_min:
+ evenements = evenements.filter_debut(min=date_min)
+ date_max = self.cleaned_data['date_max']
+ if date_max:
+ evenements = evenements.filter_debut(max=date_max)
+ return evenements.all()
###
import urllib, httplib, time, simplejson, pprint, math, re
from django.core.urlresolvers import reverse
from django.conf import settings
+from django.utils.safestring import mark_safe
from auf_savoirs_en_partage.backend_config import RESOURCES
from sep import SEP
from utils import smart_str
# Faire ceci après avoir traité les caractères accentués...
part = part.replace('a', u'[aàâÀÂ]')
- part = part.replace('e', u'[eéèëêÉÊ]')
+ part = part.replace('e', u'[eéèëêÉÊÈ]')
part = part.replace('i', u'[iïîÎ]')
part = part.replace('o', u'[oôÔ]')
part = part.replace('u', u'[uûüù]')
parts.append(part)
return re.compile('|'.join(parts), re.I)
+
+def excerpt_function(manager, words):
+ """Construit une fonction qui extrait la partie pertinente d'un texte
+ suite à une recherche textuelle."""
+ qs = manager.get_sphinx_query_set()
+ client = qs._get_sphinx_client()
+ index = qs._index
+ def excerpt(text):
+ return mark_safe(client.BuildExcerpts([text], index, words)[0])
+ return excerpt
+
# -*- encoding: utf-8 -*-
-import simplejson, uuid, datetime, caldav, vobject, uuid, random, operator, pytz, os
+import caldav
+import datetime
+import operator
+import os
+import pytz
+import random
+import simplejson
+import time
+import uuid
+import vobject
+from backend_config import RESOURCES
from babel.dates import get_timezone_name
+from caldav.lib import error
+from datamaster_modeles.models import Thematique, Pays, Region
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Q, Max
from django.db.models.signals import pre_delete
-from auf_savoirs_en_partage.backend_config import RESOURCES
+from django.utils.encoding import smart_unicode
+from djangosphinx.models import SphinxQuerySet
from savoirs.globals import META
+from savoirs.lib.calendrier import combine
from settings import CALENDRIER_URL, SITE_ROOT_URL
-from datamaster_modeles.models import Thematique, Pays, Region
-from lib.calendrier import combine
-from caldav.lib import error
+
+# Fonctionnalités communes à tous les query sets
class RandomQuerySetMixin(object):
"""Mixin pour les modèles.
positions = random.sample(xrange(count), min(n, count))
return [self[p] for p in positions]
+class SEPQuerySet(models.query.QuerySet, RandomQuerySetMixin):
+ pass
+
+class SEPSphinxQuerySet(SphinxQuerySet, RandomQuerySetMixin):
+ """Fonctionnalités communes aux query sets de Sphinx."""
+
+ def __init__(self, model=None, index=None, weights=None):
+ SphinxQuerySet.__init__(self, model=model, index=index,
+ mode='SPH_MATCH_EXTENDED2',
+ rankmode='SPH_RANK_PROXIMITY_BM25',
+ weights=weights)
+
+ def add_to_query(self, query):
+ """Ajoute une partie à la requête texte."""
+ new_query = smart_unicode(self._query) + ' ' + query if self._query else query
+ return self.query(new_query)
+
+ def search(self, text):
+ """Recherche ``text`` dans tous les champs."""
+ return self.add_to_query('@* ' + text)
+
+ def filter_discipline(self, discipline):
+ """Par défaut, le filtre par discipline cherche le nom de la
+ discipline dans tous les champs."""
+ return self.search('"%s"' % discipline.nom)
+
+ def filter_region(self, region):
+ """Par défaut, le filtre par région cherche le nom de la région dans
+ tous les champs."""
+ return self.search('"%s"' % region.nom)
+
+class SEPManager(models.Manager):
+ """Lorsque les méthodes ``search``, ``filter_region`` et
+ ``filter_discipline`` sont appelées sur ce manager, le query set
+ Sphinx est créé, sinon, c'est le query set Django qui est créé."""
+
+ def query(self, query):
+ return self.get_sphinx_query_set().query(query)
+
+ def add_to_query(self, query):
+ return self.get_sphinx_query_set().add_to_query(query)
+
+ def search(self, text):
+ return self.get_sphinx_query_set().search(text)
+
+ def filter_region(self, region):
+ return self.get_sphinx_query_set().filter_region(region)
+
+ def filter_discipline(self, discipline):
+ return self.get_sphinx_query_set().filter_discipline(discipline)
+
+# Disciplines
+
class Discipline(models.Model):
id = models.IntegerField(primary_key=True, db_column='id_discipline')
nom = models.CharField(max_length=765, db_column='nom_discipline')
db_table = u'discipline'
ordering = ["nom",]
+# Actualités
+
class SourceActualite(models.Model):
nom = models.CharField(max_length=255)
url = models.CharField(max_length=255)
def __unicode__(self,):
return u"%s" % self.nom
-class ActualiteManager(models.Manager):
-
- def get_query_set(self):
- return ActualiteQuerySet(self.model)
+class ActualiteQuerySet(SEPQuerySet):
- def search(self, text):
- return self.get_query_set().search(text)
+ def filter_date(self, min=None, max=None):
+ qs = self
+ if min:
+ qs = qs.filter(date__gte=min)
+ if max:
+ qs = qs.filter(date__lte=max)
+ return qs
- def filter_region(self, region):
- return self.get_query_set().filter_region(region)
+class ActualiteSphinxQuerySet(SEPSphinxQuerySet):
- def filter_discipline(self, discipline):
- return self.get_query_set().filter_discipline(discipline)
+ def __init__(self, model=None):
+ SEPSphinxQuerySet.__init__(self, model=model, index='actualites',
+ weights=dict(titre=3))
-class ActualiteQuerySet(models.query.QuerySet, RandomQuerySetMixin):
+ def filter_date(self, min=None, max=None):
+ qs = self
+ if min:
+ qs = qs.filter(date__gte=min.toordinal()+365)
+ if max:
+ qs = qs.filter(date__lte=max.toordinal()+365)
+ return qs
- def search(self, text):
- q = None
- for word in text.split():
- part = (Q(titre__icontains=word) | Q(texte__icontains=word) |
- Q(regions__nom__icontains=word) | Q(disciplines__nom__icontains=word))
- if q is None:
- q = part
- else:
- q = q & part
- return self.filter(q).distinct() if q is not None else self
+class ActualiteManager(SEPManager):
+
+ def get_query_set(self):
+ return ActualiteQuerySet(self.model).filter(visible=True)
- def filter_discipline(self, discipline):
- """Ne conserve que les actualités dans la discipline donnée.
-
- Si ``disicipline`` est None, ce filtre n'a aucun effet."""
- if discipline is None:
- return self
- if not isinstance(discipline, Discipline):
- discipline = Discipline.objects.get(pk=discipline)
- return self.filter(Q(disciplines=discipline) |
- Q(titre__icontains=discipline.nom) |
- Q(texte__icontains=discipline.nom)).distinct()
+ def get_sphinx_query_set(self):
+ return ActualiteSphinxQuerySet(self.model).order_by('-date')
- def filter_region(self, region):
- """Ne conserve que les actualités dans la région donnée.
-
- Si ``region`` est None, ce filtre n'a aucun effet."""
- if region is None:
- return self
- if not isinstance(region, Region):
- region = Region.objects.get(pk=region)
- return self.filter(Q(regions=region) |
- Q(titre__icontains=region.nom) |
- Q(texte__icontains=region.nom)).distinct()
+ def filter_date(self, min=None, max=None):
+ return self.get_query_set().filter_date(min=min, max=max)
class Actualite(models.Model):
id = models.AutoField(primary_key=True, db_column='id_actualite')
regions = models.ManyToManyField(Region, blank=True, related_name="actualites", verbose_name='régions')
objects = ActualiteManager()
+ all_objects = models.Manager()
class Meta:
db_table = u'actualite'
def assigner_regions(self, regions):
self.regions.add(*regions)
-class EvenementManager(models.Manager):
+# Agenda
- def get_query_set(self):
- return EvenementQuerySet(self.model)
+class EvenementQuerySet(SEPQuerySet):
- def search(self, text):
- return self.get_query_set().search(text)
+ def filter_type(self, type):
+ return self.filter(type=type)
- def filter_region(self, region):
- return self.get_query_set().filter_region(region)
+ def filter_debut(self, min=None, max=None):
+ qs = self
+ if min:
+ qs = qs.filter(debut__gte=min)
+ if max:
+ qs = qs.filter(debut__lt=max+datetime.timedelta(days=1))
+ return qs
- def filter_discipline(self, discipline):
- return self.get_query_set().filter_discipline(discipline)
+class EvenementSphinxQuerySet(SEPSphinxQuerySet):
-class EvenementQuerySet(models.query.QuerySet, RandomQuerySetMixin):
+ def __init__(self, model=None):
+ SEPSphinxQuerySet.__init__(self, model=model, index='evenements',
+ weights=dict(titre=3))
- def search(self, text):
- q = None
- for word in text.split():
- part = (Q(titre__icontains=word) |
- Q(mots_cles__icontains=word) |
- Q(discipline__nom__icontains=word) |
- Q(discipline_secondaire__nom__icontains=word) |
- Q(type__icontains=word) |
- Q(lieu__icontains=word) |
- Q(description__icontains=word) |
- Q(contact__icontains=word) |
- Q(regions__nom__icontains=word))
- if q is None:
- q = part
- else:
- q = q & part
- return self.filter(q).distinct() if q is not None else self
-
- def search_titre(self, text):
+ def filter_type(self, type):
+ return self.add_to_query('@type "%s"' % type)
+
+ def filter_debut(self, min=None, max=None):
qs = self
- for word in text.split():
- qs = qs.filter(titre__icontains=word)
+ if min:
+ qs = qs.filter(debut__gte=min.toordinal()+365)
+ if max:
+ qs = qs.filter(debut__lte=max.toordinal()+365)
return qs
- def filter_discipline(self, discipline):
- """Ne conserve que les évènements dans la discipline donnée.
-
- Si ``disicipline`` est None, ce filtre n'a aucun effet."""
- if discipline is None:
- return self
- if not isinstance(discipline, Discipline):
- discipline = Discipline.objects.get(pk=discipline)
- return self.filter(Q(discipline=discipline) |
- Q(discipline_secondaire=discipline) |
- Q(titre__icontains=discipline.nom) |
- Q(mots_cles__icontains=discipline.nom) |
- Q(description__icontains=discipline.nom))
+class EvenementManager(SEPManager):
- def filter_region(self, region):
- """Ne conserve que les évènements dans la région donnée.
-
- Si ``region`` est None, ce filtre n'a aucun effet."""
- if region is None:
- return self
- if not isinstance(region, Region):
- region = Region.objects.get(pk=region)
- return self.filter(Q(regions=region) |
- Q(titre__icontains=region.nom) |
- Q(mots_cles__icontains=region.nom) |
- Q(description__icontains=region.nom) |
- Q(lieu__icontains=region.nom)).distinct()
+ def get_query_set(self):
+ return EvenementQuerySet(self.model).filter(approuve=True)
+
+ def get_sphinx_query_set(self):
+ return EvenementSphinxQuerySet(self.model).order_by('-debut')
+
+ def filter_type(self, type):
+ return self.get_query_set().filter_type(type)
+
+ def filter_debut(self, min=None, max=None):
+ return self.get_query_set().filter_debut(min=min, max=max)
def build_time_zone_choices():
fr_names = set()
(u'Conférence', u'Conférence'),
(u'Appel à contribution', u'Appel à contribution'),
(u'Journée d\'étude', u'Journée d\'étude'),
- (None, u'Autre'))
+ (u'None', u'Autre'))
TIME_ZONE_CHOICES = build_time_zone_choices()
uid = models.CharField(max_length=255, default=str(uuid.uuid1()))
regions = models.ManyToManyField(Region, blank=True, related_name="evenements", verbose_name='régions')
objects = EvenementManager()
+ all_objects = models.Manager()
class Meta:
ordering = ['-debut']
self.discipline = disciplines[0]
self.discipline_secondaire = disciplines[1]
-
-# Surcharge du comportement de suppression
-# La méthode de connexion par signals est préférable à surcharger la méthode delete()
-# car dans le cas de la suppression par lots, cell-ci n'est pas invoquée
def delete_vevent(sender, instance, *args, **kwargs):
+ # Surcharge du comportement de suppression
+ # La méthode de connexion par signals est préférable à surcharger la méthode delete()
+ # car dans le cas de la suppression par lots, cell-ci n'est pas invoquée
instance.delete_vevent()
+pre_delete.connect(delete_vevent, sender=Evenement)
-pre_delete.connect(delete_vevent, sender = Evenement)
-
+# Ressources
class ListSet(models.Model):
spec = models.CharField(primary_key = True, max_length = 255)
def __unicode__(self,):
return self.name
-class RecordManager(models.Manager):
-
- def get_query_set(self):
- return RecordQuerySet(self.model)
-
- def search(self, text):
- return self.get_query_set().search(text)
-
- def validated(self):
- return self.get_query_set().validated()
+class RecordSphinxQuerySet(SEPSphinxQuerySet):
- def filter_region(self, region):
- return self.get_query_set().filter_region(region)
-
- def filter_discipline(self, discipline):
- return self.get_query_set().filter_discipline(discipline)
+ def __init__(self, model=None):
+ SEPSphinxQuerySet.__init__(self, model=model, index='ressources',
+ weights=dict(title=3))
-class RecordQuerySet(models.query.QuerySet, RandomQuerySetMixin):
-
- def search(self, text):
- qs = self
- words = text.split()
-
- # Ne garder que les ressources qui contiennent tous les mots
- # demandés.
- q = None
- for word in words:
- matching_pays = list(Pays.objects.filter(Q(nom__icontains=word) | Q(region__nom__icontains=word)).values_list('pk', flat=True))
- part = (Q(title__icontains=word) | Q(description__icontains=word) |
- Q(creator__icontains=word) | Q(contributor__icontains=word) |
- Q(subject__icontains=word) | Q(disciplines__nom__icontains=word) |
- Q(regions__nom__icontains=word) | Q(pays__in=matching_pays) |
- Q(publisher__icontains=word))
- if q is None:
- q = part
- else:
- q = q & part
- if q is not None:
- qs = qs.filter(q).distinct()
-
- # On donne un point pour chaque mot présent dans le titre.
- if words:
- score_expr = ' + '.join(['(title LIKE %s)'] * len(words))
- score_params = ['%' + word + '%' for word in words]
- qs = qs.extra(
- select={'score': score_expr},
- select_params=score_params
- ).order_by('-score')
- return qs
-
- def search_auteur(self, text):
- qs = self
- for word in text.split():
- qs = qs.filter(Q(creator__icontains=word) | Q(contributor__icontains=word))
- return qs
+class RecordManager(SEPManager):
- def search_sujet(self, text):
- qs = self
- for word in text.split():
- qs = qs.filter(subject__icontains=word)
- return qs
-
- def search_titre(self, text):
- qs = self
- for word in text.split():
- qs = qs.filter(title__icontains=word)
- return qs
-
- def filter_discipline(self, discipline):
- """Ne conserve que les ressources dans la discipline donnée.
-
- Si ``disicipline`` est None, ce filtre n'a aucun effet."""
- if discipline is None:
- return self
- if not isinstance(discipline, Discipline):
- discipline = Discipline.objects.get(pk=discipline)
- return self.filter(Q(disciplines=discipline) |
- Q(title__icontains=discipline.nom) |
- Q(description__icontains=discipline.nom) |
- Q(subject__icontains=discipline.nom)).distinct()
-
- def filter_region(self, region):
- """Ne conserve que les ressources dans la région donnée.
-
- Si ``region`` est None, ce filtre n'a aucun effet."""
- if region is None:
- return self
- if not isinstance(region, Region):
- region = Region.objects.get(pk=region)
- return self.filter(Q(pays__region=region) |
- Q(regions=region) |
- Q(title__icontains=region.nom) |
- Q(description__icontains=region.nom) |
- Q(subject__icontains=region.nom)).distinct()
-
- def validated(self):
+ def get_query_set(self):
"""Ne garder que les ressources validées et qui sont soit dans aucun
listset ou au moins dans un listset validé."""
- qs = self.filter(validated=True)
+ qs = SEPQuerySet(self.model)
+ qs = qs.filter(validated=True)
qs = qs.filter(Q(listsets__isnull=True) | Q(listsets__validated=True))
return qs.distinct()
- def filter(self, *args, **kwargs):
- """Gère des filtres supplémentaires pour l'admin.
-
- C'est la seule façon que j'ai trouvée de contourner les mécanismes
- de recherche de l'admin."""
- search = kwargs.pop('admin_search', None)
- search_titre = kwargs.pop('admin_search_titre', None)
- search_sujet = kwargs.pop('admin_search_sujet', None)
- search_description = kwargs.pop('admin_search_description', None)
- search_auteur = kwargs.pop('admin_search_auteur', None)
-
- if search:
- qs = self
- search_all = not (search_titre or search_description or search_sujet or search_auteur)
- fields = []
- if search_titre or search_all:
- fields += ['title', 'alt_title']
- if search_description or search_all:
- fields += ['description', 'abstract']
- if search_sujet or search_all:
- fields += ['subject']
- if search_auteur or search_all:
- fields += ['creator', 'contributor']
-
- for bit in search.split():
- or_queries = [Q(**{field + '__icontains': bit}) for field in fields]
- qs = qs.filter(reduce(operator.or_, or_queries))
-
- if args or kwargs:
- qs = super(RecordQuerySet, qs).filter(*args, **kwargs)
- return qs
- else:
- return super(RecordQuerySet, self).filter(*args, **kwargs)
+ def get_sphinx_query_set(self):
+ return RecordSphinxQuerySet(self.model)
class Record(models.Model):
pays = models.ManyToManyField(Pays, blank=True)
regions = models.ManyToManyField(Region, blank=True, verbose_name='régions')
- # Manager
+ # Managers
objects = RecordManager()
+ all_objects = models.Manager()
class Meta:
verbose_name = 'ressource'
if not rest.startswith('/recherche'):
rest = '/'
return discipline_bit + region_bit + rest
+
+@register.filter
+def apply(value, func):
+ """Applique une fonction arbitraire à la valeur filtrée."""
+ return func(value)
from django.utils.safestring import mark_safe
from django import forms
from django.conf import settings
-from lib.recherche import google_search, build_search_regexp
+from lib.recherche import google_search, build_search_regexp, excerpt_function
from lib import sep
from lib.calendrier import evenements, evenement_info, combine
from savoirs.globals import configuration
def index(request, discipline=None, region=None):
"""Page d'accueil"""
- delta = datetime.timedelta(days = 90)
- oldest = datetime.date.today() - delta
- actualites = Actualite.objects.filter(visible=True, date__gt=oldest).filter_discipline(discipline).filter_region(region)[:4]
- evenements = Evenement.objects.filter(approuve=True).filter_discipline(discipline).filter_region(region)[:4]
- ressources = Record.objects.validated().filter_discipline(discipline).filter_region(region).random(4)
- chercheurs = Chercheur.objects.filter_discipline(discipline).filter_region(region).order_by('-date_modification')[:10]
- sites = Site.objects.filter_discipline(discipline).filter_region(region).random(4)
+ actualites = Actualite.objects
+ evenements = Evenement.objects
+ ressources = Record.objects
+ chercheurs = Chercheur.objects
+ sites = Site.objects
+ if discipline:
+ discipline = Discipline.objects.get(pk=discipline)
+ actualites = actualites.filter_discipline(discipline)
+ evenements = evenements.filter_discipline(discipline)
+ ressources = ressources.filter_discipline(discipline)
+ chercheurs = chercheurs.filter_discipline(discipline)
+ sites = sites.filter_discipline(discipline)
+ if region:
+ region = Region.objects.get(pk=region)
+ actualites = actualites.filter_region(region)
+ evenements = evenements.filter_region(region)
+ ressources = ressources.filter_region(region)
+ chercheurs = chercheurs.filter_region(region)
+ sites = sites.filter_region(region)
+ actualites = actualites.all()[0:4]
+ evenements = evenements.all()[0:4]
+ ressources = ressources.all().random(4)
+ chercheurs = chercheurs.all()[0:10]
+ sites = sites.all().random(4)
return render_to_response(
"savoirs/index.html",
dict(actualites=actualites, evenements=evenements,
kwargs['region'] = region
return HttpResponseRedirect(reverse('savoirs.views.index', kwargs=kwargs))
- ressources = Record.objects.validated().filter_discipline(discipline).filter_region(region).search(query)
- actualites = Actualite.objects.filter(visible=1).filter_discipline(discipline).filter_region(region).search(query)
- evenements = Evenement.objects.filter(approuve=1).filter_discipline(discipline).filter_region(region).search(query)
- chercheurs = Chercheur.objects.filter_discipline(discipline).filter_region(region).search(query)
- sites = Site.objects.filter_discipline(discipline).filter_region(region).search(query)
+ actualites = Actualite.objects.search(query)
+ evenements = Evenement.objects.search(query)
+ ressources = Record.objects.search(query)
+ chercheurs = Chercheur.objects.search(query)
+ sites = Site.objects.search(query)
+ if discipline:
+ discipline = Discipline.objects.get(pk=discipline)
+ actualites = actualites.filter_discipline(discipline)
+ evenements = evenements.filter_discipline(discipline)
+ ressources = ressources.filter_discipline(discipline)
+ chercheurs = chercheurs.filter_discipline(discipline)
+ sites = sites.filter_discipline(discipline)
+ if region:
+ region = Region.objects.get(pk=region)
+ actualites = actualites.filter_region(region)
+ evenements = evenements.filter_region(region)
+ ressources = ressources.filter_region(region)
+ chercheurs = chercheurs.filter_region(region)
+ sites = sites.filter_region(region)
try:
sites_auf = google_search(0, query)['results']
except:
sites_auf = []
- search_regexp = build_search_regexp(query)
# Bâtissons une query string pour les liens vers les briques
params = {}
if query:
params['q'] = query
if discipline:
- params['discipline'] = discipline
+ params['discipline'] = unicode(discipline.id)
if region:
- params['region'] = region
+ params['region'] = unicode(region.id)
if params:
briques_query_string = mark_safe('?' + '&'.join(k + '=' + v.replace('"', '"') for (k, v) in params.iteritems()))
else:
briques_query_string = None
+ excerpt = excerpt_function(Record.objects, query)
+
return render_to_response(
"savoirs/recherche.html",
- dict(q=query, search_regexp=search_regexp,
- ressources=ressources[:5], total_ressources=ressources.count(),
- evenements=evenements[:5], total_evenements=evenements.count(),
- chercheurs=chercheurs[:10], total_chercheurs=chercheurs.count(),
- actualites=actualites[:5], total_actualites=actualites.count(),
- sites=sites[:5], total_sites=sites.count(),
- sites_auf=sites_auf[:5], briques_query_string=briques_query_string),
+ dict(q=query, excerpt=excerpt,
+ ressources=ressources[0:5], total_ressources=ressources.count(),
+ evenements=evenements[0:5], total_evenements=evenements.count(),
+ chercheurs=chercheurs[0:10], total_chercheurs=chercheurs.count(),
+ actualites=actualites[0:5], total_actualites=actualites.count(),
+ sites=sites[0:5], total_sites=sites.count(),
+ sites_auf=sites_auf[0:5], briques_query_string=briques_query_string),
context_instance = RequestContext(request)
)
search_form = RecordSearchForm(request.GET)
ressources = search_form.get_query_set()
nb_resultats = ressources.count()
- search_regexp = search_form.get_search_regexp()
+ if search_form.is_valid():
+ excerpt = excerpt_function(Record.objects, search_form.cleaned_data['q'])
+ else:
+ excerpt = lambda x: x
return render_to_response(
"savoirs/ressource_index.html",
- {'search_form': search_form, 'ressources': ressources,
- 'nb_resultats': nb_resultats, 'search_regexp': search_regexp},
- context_instance = RequestContext(request)
+ dict(search_form=search_form, ressources=ressources,
+ nb_resultats=nb_resultats, excerpt=excerpt),
+ context_instance=RequestContext(request)
)
def ressource_retrieve(request, id):
def actualite_index(request):
search_form = ActualiteSearchForm(request.GET)
actualites = search_form.get_query_set()
- search_regexp = search_form.get_search_regexp()
+ if search_form.is_valid():
+ excerpt = excerpt_function(Actualite.objects, search_form.cleaned_data['q'])
+ else:
+ excerpt = lambda x: x
return render_to_response(
"savoirs/actualite_index.html",
dict(actualites=actualites, search_form=search_form,
- search_regexp=search_regexp, nb_resultats=actualites.count()),
+ excerpt=excerpt, nb_resultats=actualites.count()),
context_instance = RequestContext(request))
# agenda
def evenement_index(request):
search_form = EvenementSearchForm(request.GET)
evenements = search_form.get_query_set()
- search_regexp = search_form.get_search_regexp()
+ excerpt = excerpt_function(Evenement.objects, search_form.cleaned_data['q'])
return render_to_response(
"savoirs/evenement_index.html",
dict(evenements=evenements, search_form=search_form,
- search_regexp=search_regexp, nb_resultats=evenements.count()),
+ excerpt=excerpt, nb_resultats=evenements.count()),
context_instance=RequestContext(request)
)
--- /dev/null
+#!/usr/bin/python
+# coding: utf-8
+#
+# Ce script compose dynamiquement une configuration pour Sphinx. Il suffit
+# que le fichier soit exécutable pour que Sphinx exécute le script plutôt
+# que de le lire comme un fichier statique.
+#
+# Le manuel de sphinx se trouve au http://sphinxsearch.com/docs/manual-0.9.9.html
+
+import glob
+import os
+import sys
+
+sys.path[0:0] = [
+ "%(directory)s",
+ "%(directory)s/auf_savoirs_en_partage",
+ ]
+os.environ['DJANGO_SETTINGS_MODULE'] = 'production'
+for d in glob.glob("%(directory)s/eggs/*"):
+ sys.path[0:0] = [d,]
+for d in glob.glob("%(directory)s/parts/*"):
+ sys.path[0:0] = [d,]
+
+from django.conf import settings
+
+SQL_HOST = settings.DATABASE_HOST
+SQL_USER = settings.DATABASE_USER
+SQL_PASS = settings.DATABASE_PASSWORD
+SQL_DB = settings.DATABASE_NAME
+DATA_DIR = '%(directory)s/auf_savoirs_en_partage/data/sphinx'
+
+def multiline(s):
+ """Place un marqueur de continuation avant chaque saut de ligne."""
+ return s.replace("\n", "\\\n")
+
+def emit_source(name, sql_query, sql_query_info=None, sql_attr_multi=None, sql_attr_uint=None):
+ print '''
+source %%(name)s
+{
+ type = mysql
+ sql_host = %%(sql_host)s
+ sql_user = %%(sql_user)s
+ sql_pass = %%(sql_pass)s
+ sql_db = %%(sql_db)s
+ sql_query_pre = SET NAMES utf8
+ sql_query_pre = SET SESSION query_cache_type=OFF
+ sql_query = %%(sql_query)s
+''' %% dict(name=name, sql_host=SQL_HOST, sql_user=SQL_USER,
+ sql_pass=SQL_PASS, sql_db=SQL_DB, sql_query=multiline(sql_query))
+
+ if sql_query_info:
+ print ' sql_query_info = ' + sql_query_info
+
+ if sql_attr_multi:
+ for attr in sql_attr_multi:
+ print ' sql_attr_multi = uint %%s from field' %% attr
+
+ if sql_attr_uint:
+ for attr in sql_attr_uint:
+ print ' sql_attr_uint = ' + attr
+
+ print '}'
+
+def emit_index(name):
+ print '''
+index %%(name)s
+{
+ morphology = libstemmer_fr
+ charset_type = utf-8
+ charset_table = 0..9, A..Z->a..z, _, a..z, \\
+ U+C0->a, U+C2->a, U+E0->a, U+E2->a, \\
+ U+C7->c, U+E7->c, \\
+ U+C8->e, U+C9->e, U+CA->e, U+E8->e, U+E9->e, U+EA->e, U+EB->e, \\
+ U+CE->i, U+EE->i, U+EF->i, \\
+ U+D4->o, U+F4->o, \\
+ U+F9->u, U+FB->u, U+FC->u
+ source = %%(name)s
+ path = %%(path)s
+}''' %% dict(name=name, path=os.path.join(DATA_DIR, name))
+
+emit_source('ressources',
+ '''SELECT r.id AS id,
+ r.title AS title,
+ r.description AS description,
+ r.creator AS creator,
+ r.contributor AS contributor,
+ r.subject AS subject,
+ r.publisher AS publisher,
+ GROUP_CONCAT(DISTINCT d.nom_discipline) AS disciplines,
+ GROUP_CONCAT(DISTINCT d.id_discipline) AS discipline_ids,
+ GROUP_CONCAT(DISTINCT p.nom) AS pays,
+ GROUP_CONCAT(DISTINCT reg.nom) AS regions,
+ GROUP_CONCAT(DISTINCT reg.id) AS region_ids
+ FROM savoirs_record r
+ LEFT JOIN savoirs_record_disciplines rd ON rd.record_id = r.id
+ LEFT JOIN discipline d ON d.id_discipline = rd.discipline_id
+ LEFT JOIN savoirs_record_pays rp ON rp.record_id = r.id
+ LEFT JOIN ref_pays p ON p.id = rp.pays_id
+ LEFT JOIN savoirs_record_regions rr ON rr.record_id = r.id
+ LEFT JOIN ref_region reg ON reg.id = rr.region_id OR reg.id = p.region
+ LEFT JOIN savoirs_record_listsets rl ON rl.record_id = r.id
+ LEFT JOIN savoirs_listset l ON l.spec = rl.listset_id
+ WHERE r.validated AND (l.spec IS NULL OR l.validated)
+ GROUP BY r.id''',
+ sql_query_info='SELECT * from savoirs_record WHERE id=$id',
+ sql_attr_multi=['discipline_ids', 'region_ids']
+ )
+
+emit_source('actualites',
+ '''SELECT a.id_actualite AS id,
+ a.titre_actualite AS titre,
+ a.texte_actualite AS texte,
+ TO_DAYS(a.date_actualite) AS date,
+ GROUP_CONCAT(DISTINCT r.nom) AS regions,
+ GROUP_CONCAT(DISTINCT d.nom_discipline) AS disciplines
+ FROM actualite a
+ LEFT JOIN actualite_regions ar ON ar.actualite_id = a.id_actualite
+ LEFT JOIN ref_region r ON r.id = ar.region_id
+ LEFT JOIN actualite_disciplines ad ON ad.actualite_id = a.id_actualite
+ LEFT JOIN discipline d ON d.id_discipline = ad.discipline_id
+ WHERE a.visible_actualite
+ GROUP BY a.id_actualite''',
+ sql_query_info='SELECT * from actualite WHERE id_actualite=$id',
+ sql_attr_uint=['date']
+ )
+
+emit_source('evenements',
+ '''SELECT e.id AS id,
+ e.titre AS titre,
+ e.mots_cles AS mots_cles,
+ e.type AS type,
+ e.lieu AS lieu,
+ e.description AS description,
+ e.contact AS contact,
+ CONCAT_WS(',', d.nom_discipline, d2.nom_discipline) AS disciplines,
+ GROUP_CONCAT(DISTINCT r.nom) AS regions,
+ TO_DAYS(DATE(e.debut)) AS debut
+ FROM savoirs_evenement e
+ LEFT JOIN discipline d ON d.id_discipline = e.discipline_id
+ LEFT JOIN discipline d2 ON d2.id_discipline = e.discipline_secondaire_id
+ LEFT JOIN savoirs_evenement_regions er ON er.evenement_id = e.id
+ LEFT JOIN ref_region r ON r.id = er.region_id
+ WHERE e.approuve
+ GROUP BY e.id''',
+ sql_query_info='SELECT * from savoirs_evenement WHERE id=$id',
+ sql_attr_uint=['debut'])
+
+emit_source('chercheurs',
+ '''SELECT c.id AS id,
+ p.nom AS nom,
+ p.prenom AS prenom,
+ c.theme_recherche AS theme_recherche,
+ c.groupe_recherche AS groupe_recherche,
+ c.mots_cles AS mots_cles,
+ c.membre_association_francophone_details AS membre_association_francophone_details,
+ c.membre_reseau_institutionnel_details AS membre_reseau_institutionnel_details,
+ c.expert_oif_details AS expert_oif_details,
+ c.membre_instance_auf_details AS membre_instance_auf_details,
+ IFNULL(et.nom, etablissement_autre_nom) AS etablissement,
+ pays.nom AS pays,
+ pays.id AS pays_id,
+ r.nom AS region,
+ r.id AS region_id,
+ GROUP_CONCAT(DISTINCT d.nom_discipline) AS disciplines,
+ CONCAT_WS(pub1.titre, pub2.titre, pub3.titre, pub4.titre) AS publications,
+ t.titre AS these,
+ GROUP_CONCAT(DISTINCT g.nom) AS groupes,
+ GROUP_CONCAT(DISTINCT ex.nom) AS expertises,
+ GROUP_CONCAT(DISTINCT g.id) AS groupe_ids,
+ TO_DAYS(c.date_modification) AS date_modification,
+ CASE pays WHEN 'Nord' THEN 1
+ WHEN 'Sud' THEN 2
+ END AS nord_sud,
+ CASE statut WHEN 'enseignant' THEN 1
+ WHEN 'etudiant' THEN 2
+ WHEN 'independant' THEN 3
+ END AS statut,
+ (ex.id IS NULL) AS expert
+ FROM chercheurs_chercheur c
+ INNER JOIN chercheurs_personne p ON c.personne = p.id
+ LEFT JOIN ref_etablissement et ON et.id = c.etablissement
+ LEFT JOIN ref_pays pays ON pays.id = IFNULL(et.pays, c.etablissement_autre_pays)
+ LEFT JOIN ref_region r ON pays.region = r.id
+ LEFT JOIN discipline d ON d.id_discipline = c.discipline
+ LEFT JOIN chercheurs_publication pub1 ON pub1.id = c.publication1
+ LEFT JOIN chercheurs_publication pub2 ON pub2.id = c.publication2
+ LEFT JOIN chercheurs_publication pub3 ON pub3.id = c.publication3
+ LEFT JOIN chercheurs_publication pub4 ON pub4.id = c.publication4
+ LEFT JOIN chercheurs_publication t ON t.id = c.these
+ LEFT JOIN chercheurs_chercheurgroupe cg ON cg.chercheur = c.id
+ LEFT JOIN chercheurs_groupe g ON g.id = cg.groupe
+ LEFT JOIN chercheurs_expertise ex ON ex.chercheur_id = c.id
+ GROUP BY c.id''',
+ sql_query_info='SELECT * from chercheurs_chercheur WHERE id=$id',
+ sql_attr_multi=['groupe_ids'],
+ sql_attr_uint=['pays_id', 'region_id', 'nord_sud', 'date_modification', 'statut', 'expert'])
+
+emit_source('sites',
+ '''SELECT s.id AS id,
+ s.titre AS titre,
+ s.description AS description,
+ s.editeur AS editeur,
+ s.auteur AS auteur,
+ s.mots_cles AS mots_cles,
+ GROUP_CONCAT(DISTINCT d.nom_discipline) AS disciplines,
+ GROUP_CONCAT(DISTINCT p.nom) AS pays,
+ GROUP_CONCAT(DISTINCT p.id) AS pays_ids,
+ GROUP_CONCAT(DISTINCT r.nom) AS regions
+ FROM sitotheque_site s
+ LEFT JOIN sitotheque_site_discipline sd ON sd.site_id = s.id
+ LEFT JOIN discipline d ON d.id_discipline = sd.discipline_id
+ LEFT JOIN ref_pays p ON p.id = s.pays
+ LEFT JOIN ref_region r ON r.id = p.region
+ GROUP BY s.id''',
+ 'SELECT * FROM sitotheque_site WHERE id=$id',
+ sql_attr_multi=['pays_ids'])
+
+emit_index('actualites')
+emit_index('ressources')
+emit_index('evenements')
+emit_index('chercheurs')
+emit_index('sites')
+
+print '''
+indexer
+{
+ mem_limit = 256M
+}
+
+searchd
+{
+ listen = 127.0.0.1:9312
+ pid_file = %%(pid_file)s
+ log = %%(log)s
+}
+''' %% dict(pid_file=os.path.join(DATA_DIR, 'sphinx.pid'), log=os.path.join(DATA_DIR, 'searchd.log'))
'savoirs',
'chercheurs',
'sitotheque',
+ 'djangosphinx',
)
CONTACT_EMAIL = 'contact-savoirsenpartage@auf.org'
+SPHINX_API_VERSION = 0x116
+SPHINX_PORT = 9312
+
from auf_references_client.settings import *
def get_query_set(self):
"""Retourne l'ensemble des sites qui correspondent aux valeurs
entrées dans le formulaire."""
- sites = Site.objects.order_by("titre")
+ sites = Site.objects
if self.is_valid():
q = self.cleaned_data["q"]
if q:
sites = sites.filter_region(region)
pays = self.cleaned_data["pays"]
if pays:
- sites = sites.filter(pays=pays.pk)
- return sites
-
- def get_search_regexp(self):
- """Retourne une expression régulière compilée qui peut servir à
- chercher les mot-clés recherchés dans un texte."""
- if self.is_valid():
- return build_search_regexp(self.cleaned_data['q'])
+ sites = sites.filter_pays(pays=pays)
+ return sites.all()
# -*- encoding: utf-8 -*-
+from datamaster_modeles.models import *
from django.db import models
from django.db.models import Q
-from datamaster_modeles.models import *
-from savoirs.models import Discipline, RandomQuerySetMixin
+from djangosphinx.models import SphinxSearch
+from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySet
TYPE_SITE_CHOICES = (
('RV', 'Revue en ligne'),
('AU', 'Autre type de site'),
)
-class SiteManager(models.Manager):
+class SiteQuerySet(SEPQuerySet):
- def get_query_set(self):
- return SiteQuerySet(self.model)
+ def filter_pays(self, pays):
+ return self.filter(pays=pays)
- def search(self, text):
- return self.get_query_set().search(text)
+class SiteSphinxQuerySet(SEPSphinxQuerySet):
- def filter_region(self, region):
- return self.get_query_set().filter_region(region)
+ def __init__(self, model=None):
+ SEPSphinxQuerySet.__init__(self, model=model, index='sites', weights=dict(titre=3))
- def filter_discipline(self, discipline):
- return self.get_query_set().filter_discipline(discipline)
+ def filter_pays(self, pays):
+ return self.filter(pays_ids=pays.id)
-class SiteQuerySet(models.query.QuerySet, RandomQuerySetMixin):
+class SiteManager(SEPManager):
- def search(self, text):
- qs = self
- q = None
- for word in text.split():
- part = (Q(titre__icontains=word) |
- Q(description__icontains=word) |
- Q(editeur__icontains=word) |
- Q(auteur__icontains=word) |
- Q(mots_cles__icontains=word) |
- Q(discipline__nom__icontains=word) |
- Q(pays__nom__icontains=word))
- if q is None:
- q = part
- else:
- q = q & part
- if q is not None:
- qs = qs.filter(q).distinct()
- return qs
+ def get_query_set(self):
+ return SiteQuerySet(self.model)
- def filter_discipline(self, discipline):
- """Ne conserve que les sites dans la discipline donnée.
-
- Si ``disicipline`` est None, ce filtre n'a aucun effet."""
- if discipline is None:
- return self
- if not isinstance(discipline, Discipline):
- discipline = Discipline.objects.get(pk=discipline)
- return self.filter(Q(discipline=discipline) |
- Q(titre__icontains=discipline.nom) |
- Q(description__icontains=discipline.nom) |
- Q(mots_cles__icontains=discipline.nom))
+ def get_sphinx_query_set(self):
+ return SiteSphinxQuerySet(self.model)
- def filter_region(self, region):
- """Ne conserve que les sites dans la région donnée.
-
- Si ``region`` est None, ce filtre n'a aucun effet."""
- if region is None:
- return self
- if not isinstance(region, Region):
- region = Region.objects.get(pk=region)
- return self.filter(Q(pays__region=region) |
- Q(titre__icontains=region.nom) |
- Q(description__icontains=region.nom) |
- Q(mots_cles__icontains=region.nom)).distinct()
+ def filter_pays(self, pays):
+ return self.get_query_set().filter_pays(pays)
class Site(models.Model):
"""Fiche d'info d'un site web"""
# Manager
objects = SiteManager()
+ all_objects = models.Manager()
def __unicode__(self):
return "%s" % (self.titre)
from django.shortcuts import render_to_response
from django.template import Context, RequestContext
from django.db.models import Q
-
-from models import Site
from forms import SiteSearchForm
+from models import Site
+from savoirs.lib.recherche import excerpt_function
def index(request):
search_form = SiteSearchForm(request.GET)
sites = search_form.get_query_set()
- search_regexp = search_form.get_search_regexp()
nb_sites = sites.count()
+ excerpt = excerpt_function(Site.objects, search_form.cleaned_data['q'])
return render_to_response("sites/index.html",
- dict(sites=sites, search_form=search_form,
- search_regexp=search_regexp, nb_sites=nb_sites),
+ dict(sites=sites, search_form=search_form,
+ excerpt=excerpt, nb_sites=nb_sites),
context_instance = RequestContext(request))
def retrieve(request, id):
-{% load search %}
+{% load sep %}
<div class="resultatRecherche">
<div class="la-date">{{ actualite.date|date:"d F Y" }}</div>
- <a class="le-titre" href="{{ actualite.url }}">{{ actualite.titre|highlight:search_regexp }}</a>
- <div class="resultatResume">{{ actualite.texte|highlight:search_regexp }}</div>
+ <a class="le-titre" href="{{ actualite.url }}">{{ actualite.titre|apply:excerpt }}</a>
+ <div class="resultatResume">{{ actualite.texte|apply:excerpt }}</div>
{% if actualite.source %}
<div><span class="lbl">Source:</span> {{ actualite.source.nom }}</div>
{% endif %}
-{% load search %}
+{% load sep %}
<div class="resultatRecherche">
<div class="la-date">{{ evenement.debut|date:"d/m/Y H\hi" }}</div>
- <div><a href="{% url savoirs.views.evenement evenement.pk %}" class="le-titre">{{ evenement.titre|highlight:search_regexp }}</a></div>
- <div class="le-resume">{{ evenement.description|excerpt:search_regexp|highlight:search_regexp }}</div>
+ <div><a href="{% url savoirs.views.evenement evenement.pk %}" class="le-titre">{{ evenement.titre|apply:excerpt }}</a></div>
+ <div class="le-resume">{{ evenement.description|apply:excerpt }}</div>
</div>
-{% load search %}
+{% load sep %}
<div class="resultatRecherche">
- <a class="le-titre" href="{% url savoirs.views.ressource_retrieve ressource.id %}">{{ ressource.title|highlight:search_regexp }}</a>
+ <a class="le-titre" href="{% url savoirs.views.ressource_retrieve ressource.id %}">{{ ressource.title|apply:excerpt }}</a>
{% if ressource.creator %}
- <div><span class="lbl">Auteur:</span> {{ ressource.creator|highlight:search_regexp }}</div>
+ <div><span class="lbl">Auteur:</span> {{ ressource.creator|apply:excerpt }}</div>
{% endif %}
{% if ressource.description %}
- <div class="resultatResume"><span class="lbl">Description:</span> {{ ressource.description|excerpt:search_regexp|highlight:search_regexp }}</div>
+ <div class="resultatResume"><span class="lbl">Description:</span> {{ ressource.description|apply:excerpt }}</div>
{% endif %}
<div class="fiche"><span>Fiche: </span><a href="{% url savoirs.views.ressource_retrieve ressource.id %}">{% url savoirs.views.ressource_retrieve ressource.id %}</a></div>
<div class="original"><span>Contenu original: </span><a target="_blank" href="{{ ressource.uri }}">{{ ressource.uri }}</a></div>
<div class="provenance"><span>Provenance: </span><a target="_blank" href="{{ ressource.getServeurURL }}">{{ ressource.getServeurURL }}</a></div>
</div>
-
- {% comment %}
- {% if user.is_authenticated %}
- <a href="{{ r.admin_url}}" target="_blank">Modifier</a>
- {% endif %}
- {% endcomment %}
-{% load search %}
+{% load sep %}
<div class="resultatRecherche">
- <div><a class="le-titre" href="{% url sitotheque.views.retrieve site.id %}">{{ site|highlight:search_regexp }}</a></div>
- <div class="resultatResume">{{ site.description|excerpt:search_regexp|highlight:search_regexp }}</div>
+ <div><a class="le-titre" href="{% url sitotheque.views.retrieve site.id %}">{{ site.titre|apply:excerpt }}</a></div>
+ <div class="resultatResume">{{ site.description|apply:excerpt }}</div>
<div><span class="lbl">URL:</span> <a href="{{ site.url }}">{{ site.url }}</a></div>
</div>
[buildout]
newest = false
-parts = django articles harvest
+parts = django articles harvest sphinx_conf
find-links = http://pypi.auf.org/caldav/
http://pypi.auf.org/auf_references_client/
http://pypi.auf.org/auf_references_modeles/
datamaster_modeles
django-roa
django-admin-tools
+ django-sphinx
#develop = src/caldav
recipe = buildout_script
template_dir = ${buildout:directory}/auf_savoirs_en_partage/scripts/
template = import_chercheurs.in
+
+[sphinx_conf]
+recipe = buildout_script
+template_dir = ${buildout:directory}/auf_savoirs_en_partage/scripts/
+template = sphinx.conf.py.in