Upgrade de Django vers la version 1.2.5
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / chercheurs / models.py
CommitLineData
932eef9a 1# -*- encoding: utf-8 -*-
92990258 2import hashlib
fdcf5874 3
5212238e 4from datamaster_modeles.models import *
43ed73e7 5from django.conf import settings
fdcf5874
EMS
6from django.contrib.auth.models import User
7from django.core.urlresolvers import reverse as url
932eef9a 8from django.db import models
a2c6bb72 9from django.db.models import Q
92990258 10from django.utils.encoding import smart_str
43ed73e7 11from django.utils.hashcompat import sha_constructor
5212238e 12from djangosphinx.models import SphinxSearch
fdcf5874
EMS
13
14from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySet, Search
932eef9a 15
13146d99 16GENRE_CHOICES = (('m', 'Homme'), ('f', 'Femme'))
932eef9a 17class Personne(models.Model):
595ab4d6 18 salutation = models.CharField(max_length=128, null=True, blank=True)
932eef9a 19 nom = models.CharField(max_length=255)
595ab4d6 20 prenom = models.CharField(max_length=128, verbose_name='prénom')
165da916
EMS
21 courriel = models.EmailField(max_length=128, verbose_name="courriel")
22 afficher_courriel = models.BooleanField(default=True)
595ab4d6 23 fonction = models.CharField(max_length=128, null=True, blank=True)
c18af6bd 24 date_naissance = models.DateField(null=True, blank=True)
595ab4d6 25 sousfonction = models.CharField(max_length=128, null=True, blank=True, verbose_name='sous-fonction')
0a379c77
EMS
26 telephone = models.CharField(max_length=32, null=True, blank=True, verbose_name='numéro de téléphone')
27 adresse_postale = models.TextField(blank=True)
932eef9a 28 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
595ab4d6 29 commentaire = models.TextField(verbose_name='commentaires', null=True, blank=True)
3e556e66 30 actif = models.BooleanField(editable=False, default=False)
932eef9a
AJ
31
32 def __unicode__(self):
33 return u"%s %s, %s" % (self.prenom, self.nom, self.courriel)
34
35 class Meta:
13ec4813 36 ordering = ["nom", "prenom"]
92990258 37
705013cb
EMS
38 @property
39 def civilite(self):
40 if self.genre == 'm':
41 return 'M.'
42 elif self.genre == 'f':
43 return 'Mme'
44 else:
45 return ''
46
3a3d9c6f
EMS
47 def courriel_display(self):
48 return self.courriel.replace(u'@', u' (à) ')
49
5212238e 50class ChercheurQuerySet(SEPQuerySet):
a2c6bb72 51
5212238e
EMS
52 def filter_groupe(self, groupe):
53 return self.filter(groupes=groupe)
54
55 def filter_pays(self, pays):
56 return self.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
57
58 def filter_region(self, region):
59 return self.filter(Q(etablissement__pays__region=region) | Q(etablissement_autre_pays__region=region))
a2c6bb72 60
5212238e
EMS
61 def filter_nord_sud(self, nord_sud):
62 return self.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud))
116db1fd 63
5c9bae2d
OL
64 def filter_genre(self, genre):
65 return self.filter(genre=genre)
66
5212238e
EMS
67 def filter_statut(self, statut):
68 return self.filter(statut=statut)
69
70 def filter_expert(self):
71 return self.exclude(expertises=None)
72
acd5cd8f 73 def order_by_nom(self, direction=''):
3648b3d6 74 return self.order_by(direction + 'nom', direction + 'prenom', '-date_modification')
acd5cd8f
EMS
75
76 def order_by_etablissement(self, direction=''):
1760a3e9
EMS
77 return self.extra(select=dict(etablissement_nom='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
78 order_by=[direction + 'etablissement_nom', '-date_modification'])
acd5cd8f
EMS
79
80 def order_by_pays(self, direction=''):
81 return self.extra(select=dict(
82 pays_etablissement='''(SELECT nom FROM ref_pays
83 WHERE ref_pays.code = IFNULL(ref_etablissement.pays, chercheurs_chercheur.etablissement_autre_pays))'''
84 ), order_by=[direction + 'pays_etablissement', '-date_modification'])
85
5212238e
EMS
86class ChercheurSphinxQuerySet(SEPSphinxQuerySet):
87
88 def __init__(self, model=None):
4134daa0 89 return SEPSphinxQuerySet.__init__(self, model=model, index='savoirsenpartage_chercheurs',
acd5cd8f 90 weights=dict(nom=2, prenom=2))
d9da735f 91
c1b134f8 92 def filter_region(self, region):
5212238e
EMS
93 return self.filter(region_id=region.id)
94
95 def filter_groupe(self, groupe):
96 return self.filter(groupe_ids=groupe.id)
97
98 def filter_pays(self, pays):
99 return self.filter(pays_id=pays.id)
c1b134f8 100
5212238e
EMS
101 NORD_SUD_CODES = {'Nord': 1, 'Sud': 2}
102 def filter_nord_sud(self, nord_sud):
103 return self.filter(nord_sud=self.NORD_SUD_CODES[nord_sud])
104
c6efde25
OL
105 GENRE_CODES = dict([(k, i+1) for i, (k, v) in enumerate(GENRE_CHOICES)])
106 def filter_genre(self, genre):
107 return self.filter(genre=self.GENRE_CODES[genre])
108
5212238e
EMS
109 STATUT_CODES = {'enseignant': 1, 'etudiant': 2, 'independant': 3}
110 def filter_statut(self, statut):
111 return self.filter(statut=self.STATUT_CODES[statut])
112
d9da735f
EMS
113 def filter_expert(self):
114 return self.filter(expert=True)
115
acd5cd8f
EMS
116 def order_by_nom(self, direction=''):
117 return self.order_by(direction + 'nom_complet', '-date_modification')
118
119 def order_by_etablissement(self, direction=''):
120 return self.order_by(direction + 'etablissement_attr', '-date_modification')
121
122 def order_by_pays(self, direction=''):
123 return self.order_by(direction + 'pays_attr', '-date_modification')
124
5212238e 125class ChercheurManager(SEPManager):
a2c6bb72
EMS
126
127 def get_query_set(self):
695930dd 128 return ChercheurQuerySet(self.model).filter(actif=True)
a2c6bb72 129
5212238e
EMS
130 def get_sphinx_query_set(self):
131 return ChercheurSphinxQuerySet(self.model).order_by('-date_modification')
5212238e 132
116db1fd 133 def filter_region(self, region):
5212238e 134 """Le filtrage de chercheurs par région n'est pas une recherche texte."""
c1b134f8
EMS
135 return self.get_query_set().filter_region(region)
136
5212238e
EMS
137 def filter_groupe(self, groupe):
138 return self.get_query_set().filter_groupe(groupe)
bae03b7b 139
5212238e
EMS
140 def filter_pays(self, pays):
141 return self.get_query_set().filter_pays(pays)
142
143 def filter_nord_sud(self, nord_sud):
144 return self.get_query_set().filter_nord_sud(nord_sud)
145
a7bf6c5a 146 def filter_genre(self, genre):
634d46da 147 return self.get_query_set().filter_genre(genre=genre)
a7bf6c5a 148
5212238e
EMS
149 def filter_statut(self, statut):
150 return self.get_query_set().filter_statut(statut)
151
152 def filter_expert(self):
153 return self.get_query_set().filter_expert()
3efbacbe 154
acd5cd8f
EMS
155 def order_by_nom(self, direction=''):
156 return self.get_query_set().order_by_nom(self, direction=direction)
157
158 def order_by_etablissement(self, direction=''):
159 return self.get_query_set().order_by_etablissement(self, direction=direction)
160
161 def order_by_pays(self, direction=''):
162 return self.get_query_set().order_by_pays(self, direction=direction)
163
bc15119b
EMS
164STATUT_CHOICES = (
165 ('enseignant', 'Enseignant-chercheur dans un établissement'),
166 ('etudiant', 'Étudiant-chercheur doctorant'),
167 ('independant', 'Chercheur indépendant docteur')
168)
169
13ec4813 170class Chercheur(Personne):
bc15119b
EMS
171 RESEAU_INSTITUTIONNEL_CHOICES = (
172 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
173 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
174 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
175 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
176 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
177 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
178 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
179 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
180 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
181 ('CIDEFA', 'Conférence internationale des directeurs et doyens des établissements supérieurs d’expression française des sciences de l’agriculture et de l’alimentation (CIDEFA)'),
182 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
183 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
184 )
185 INSTANCE_AUF_CHOICES = (
186 ('CASSOC', 'Conseil associatif'),
187 ('CA', "Conseil d'administration"),
188 ('CS', 'Conseil scientifique'),
2fcf82c9
EMS
189 ('CRE', "Commission régionale d'experts"),
190 ('CR', 'Conférence des recteurs'),
191 ('CNO', "Conseil national d'orientation")
bc15119b
EMS
192 )
193
00755d9b 194 nationalite = models.ForeignKey(Pays, null = True, db_column='nationalite', to_field='code',
0b0fbbd7 195 verbose_name = 'nationalité', related_name='nationalite')
a4e383ac 196 statut = models.CharField(max_length=36, choices=STATUT_CHOICES)
0b0fbbd7 197 diplome = models.CharField(max_length=255, null=True, verbose_name = 'diplôme le plus élevé')
73cabd75 198 etablissement = models.ForeignKey(Etablissement, db_column='etablissement', null=True, blank=True)
0b0fbbd7 199 etablissement_autre_nom = models.CharField(max_length=255, null=True, blank=True, verbose_name = 'autre établissement')
00755d9b 200 etablissement_autre_pays = models.ForeignKey(Pays, null = True, blank=True, db_column='etablissement_autre_pays',
0b0fbbd7
EMS
201 to_field='code', related_name='etablissement_autre_pays',
202 verbose_name = "pays de l'établissement")
0874e7d1 203 attestation = models.BooleanField()
73cabd75 204
0b0fbbd7
EMS
205 #Domaine
206 thematique = models.ForeignKey(Thematique, db_column='thematique', null=True, verbose_name='thematique')
518d0b44 207 mots_cles = models.CharField(max_length=255, null=True, verbose_name='mots-clés')
0b0fbbd7 208 discipline = models.ForeignKey(Discipline, db_column='discipline', null=True, verbose_name='Discipline')
518d0b44 209 theme_recherche = models.TextField(null=True, blank=True, verbose_name='thèmes de recherche')
0b0fbbd7 210 groupe_recherche = models.CharField(max_length=255, blank=True, verbose_name='groupe de recherche')
219710da
EMS
211 url_site_web = models.URLField(max_length=255, null=True, blank=True,
212 verbose_name='adresse site Internet', verify_exists=False)
213 url_blog = models.URLField(max_length=255, null=True, blank=True, verbose_name='blog',
214 verify_exists=False)
3c576696
EMS
215 url_reseau_social = models.URLField(
216 max_length=255, null=True, blank=True, verbose_name='Réseau social',
219710da 217 verify_exists=False,
3c576696
EMS
218 help_text=u"Vous pouvez indiquer ici l'adresse de votre page personnelle dans votre réseau social préféré (e.g. Facebook, LinkedIn, Twitter, Identica, ...)"
219 )
00755d9b 220
e4d01d1d 221 groupes = models.ManyToManyField('Groupe', through='ChercheurGroupe', blank=True, verbose_name='Domaines de recherche')
932eef9a 222
a7b16ec9 223 # Activités en francophonie
121d9439 224 membre_instance_auf = models.NullBooleanField(verbose_name="est ou a déjà été membre d'une instance de l'AUF")
bc15119b
EMS
225 membre_instance_auf_nom = models.CharField(max_length=10, blank=True, choices=INSTANCE_AUF_CHOICES, verbose_name="instance")
226 membre_instance_auf_fonction = models.CharField(max_length=255, blank=True, verbose_name="fonction")
a7b16ec9 227 membre_instance_auf_dates = models.CharField(max_length=255, blank=True, verbose_name="dates")
121d9439 228 expert_oif = models.NullBooleanField(verbose_name="a été sollicité par l'OIF")
614b3269
EMS
229 expert_oif_details = models.CharField(max_length=255, blank=True, verbose_name="détails")
230 expert_oif_dates = models.CharField(max_length=255, blank=True, verbose_name="dates")
121d9439 231 membre_association_francophone = models.NullBooleanField(verbose_name="est membre d'une association francophone")
c073c94d 232 membre_association_francophone_details = models.CharField(max_length=255, blank=True, verbose_name="nom de l'association")
121d9439
EMS
233 membre_reseau_institutionnel = models.NullBooleanField(
234 verbose_name="est membre des instances d'un réseau institutionnel de l'AUF"
bc15119b
EMS
235 )
236 membre_reseau_institutionnel_nom = models.CharField(
237 max_length=15, choices=RESEAU_INSTITUTIONNEL_CHOICES, blank=True,
238 verbose_name="réseau institutionnel"
c073c94d 239 )
bc15119b
EMS
240 membre_reseau_institutionnel_fonction = models.CharField(
241 max_length=255, blank=True, verbose_name="fonction"
c073c94d
EMS
242 )
243 membre_reseau_institutionnel_dates = models.CharField(
244 max_length=255, blank=True, verbose_name="dates"
245 )
a7b16ec9 246
cb591fb3 247 # Expertises
121d9439 248 expertises_auf = models.NullBooleanField(verbose_name="est disposé à réaliser des expertises pour l'AUF")
cb591fb3 249
00755d9b
AJ
250 #meta
251 date_creation = models.DateField(auto_now_add=True, db_column='date_creation')
252 date_modification = models.DateField(auto_now=True, db_column='date_modification')
253
a2c6bb72
EMS
254 # Manager
255 objects = ChercheurManager()
c59dba82 256 all_objects = models.Manager()
a2c6bb72 257
588d6b93 258 def __unicode__(self):
13ec4813 259 return u"%s %s" % (self.nom.upper(), self.prenom.title())
e427f068 260
b57a7362
AJ
261 def statut_display(self):
262 for s in STATUT_CHOICES:
263 if self.statut == s[0]:
264 return s[1]
e427f068 265 return "-"
588d6b93 266
e4d01d1d
EMS
267 @property
268 def etablissement_display(self):
d264c787 269 return self.nom_etablissement + ', ' + self.pays
e4d01d1d 270
d32102bd
EMS
271 @property
272 def pays(self):
273 return self.etablissement.pays if self.etablissement else self.etablissement_autre_pays
274
275 @property
d264c787
EMS
276 def nom_etablissement(self):
277 return self.etablissement.nom if self.etablissement else self.etablissement_autre_nom
278
279 @property
d32102bd
EMS
280 def region(self):
281 return self.pays.region
282
71e3d741
EMS
283 def save(self):
284 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
285 if self.etablissement:
286 self.etablissement_autre_nom = None
287 self.etablissement_autre_pays = None
288 super(Chercheur, self).save()
289
43ed73e7
EMS
290 def activation_token(self):
291 return sha_constructor(settings.SECRET_KEY + unicode(self.id)).hexdigest()[::2]
292
00755d9b 293class Publication(models.Model):
595ab4d6 294 chercheur = models.ForeignKey(Chercheur, related_name='publications')
1df3737b 295 auteurs = models.CharField(max_length=255, blank=True, verbose_name='auteur(s)')
595ab4d6 296 titre = models.CharField(max_length=255, null=True, blank=True, verbose_name='titre')
1df3737b
EMS
297 revue = models.CharField(max_length=255, null=True, blank=True, verbose_name='revue')
298 annee = models.IntegerField(null=True, blank=True, verbose_name='année de publication')
299 editeur = models.CharField(max_length=255, null=True, blank=True, verbose_name='éditeur')
300 lieu_edition = models.CharField(max_length=255, null=True, blank=True, verbose_name="lieu d'édition")
301 nb_pages = models.CharField(max_length=255, null=True, blank=True, verbose_name='nombre de pages')
912e3c6c 302 url = models.URLField(max_length=255, null=True, blank=True, verbose_name='lien vers la publication', verify_exists=False)
6befc7c9 303 #Migration des publications depuis l'ancien repertoire de chercheurs
1df3737b 304 publication_affichage = models.TextField(verbose_name='publication', null=True, blank=True)
595ab4d6 305 actif = models.BooleanField(editable=False)
2a36714f
AJ
306
307 def __unicode__(self):
c59dba82 308 return self.titre or '(Aucun)'
2a36714f 309
3eb41a6d
EMS
310 def save(self):
311 if self.publication_affichage and (self.auteurs or self.titre or
312 self.revue or self.annee or
313 self.editeur or self.lieu_edition
314 or self.nb_pages or self.url):
315 self.publication_affichage = ''
316 super(Publication, self).save()
317
595ab4d6
EMS
318class These(models.Model):
319 chercheur = models.OneToOneField(Chercheur, primary_key=True)
14fd1c3f 320 titre = models.CharField(max_length=255, verbose_name='Titre')
595ab4d6 321 annee = models.IntegerField(verbose_name='Année de soutenance (réalisée ou prévue)')
14fd1c3f 322 directeur = models.CharField(max_length=255, verbose_name='Directeur')
595ab4d6
EMS
323 etablissement = models.CharField(max_length=255, verbose_name='Établissement de soutenance')
324 nb_pages = models.IntegerField(verbose_name='Nombre de pages', blank=True, null=True)
912e3c6c 325 url = models.URLField(max_length=255, verbose_name='Lien vers la publication', blank=True, verify_exists=False)
595ab4d6
EMS
326
327 def __unicode__(self):
328 return self.titre
329
2a36714f
AJ
330class Expertise(models.Model):
331 id = models.AutoField(primary_key=True, db_column='id')
ee8b3a49 332 chercheur = models.ForeignKey(Chercheur, related_name='expertises')
356cc691 333 nom = models.CharField(max_length=255, verbose_name = "Objet de l'expertise")
c1234eb8 334 date = models.CharField(max_length=255, blank=True)
ee8b3a49 335 lieu = models.CharField(max_length=255, null=True, blank=True, verbose_name = "Lieu de l'expertise")
b16bcbaf
EMS
336 organisme_demandeur = models.CharField(max_length=255, null=True, blank=True, verbose_name = 'Organisme demandeur')
337 organisme_demandeur_visible = models.BooleanField(verbose_name="Afficher l'organisme demandeur")
2a36714f 338 actif = models.BooleanField(editable = False, db_column='actif')
5b9abc81
AJ
339
340 def __unicode__(self):
341 return u"%s" % (self.nom)
2a36714f 342
932eef9a
AJ
343class Groupe(models.Model):
344 id = models.AutoField(primary_key=True, db_column='id')
345 nom = models.CharField(max_length=255, db_column='nom')
00755d9b
AJ
346 url = models.URLField(max_length=255, null=True, blank=True,
347 verbose_name='Site web')
348 liste_diffusion = models.URLField(max_length=255, null=True, blank=True,
349 verbose_name='Liste de diffusion')
350 bulletin = models.URLField(max_length=255, null=True, blank=True,
351 verbose_name='Bulletin')
932eef9a
AJ
352 actif = models.BooleanField(editable = False, db_column='actif')
353
55ef8558
EMS
354 class Meta:
355 verbose_name = 'domaine de recherche'
356 verbose_name_plural = 'domaines de recherche'
357
932eef9a
AJ
358 def __unicode__(self):
359 return u"%s" % (self.nom)
360
361class ChercheurGroupe(models.Model):
73cabd75 362 id = models.AutoField(primary_key=True, db_column='id')
55ef8558 363 chercheur = models.ForeignKey('Chercheur', db_column='chercheur', editable=False)
73cabd75 364 groupe = models.ForeignKey('Groupe', db_column='groupe')
00755d9b
AJ
365 date_inscription = models.DateField(auto_now_add=True)
366 date_modification = models.DateField(auto_now=True)
5ecd9e43 367 actif = models.BooleanField(editable = False, db_column='actif')
2a36714f 368
55ef8558
EMS
369 class Meta:
370 verbose_name = 'adhésion'
371
2a36714f
AJ
372 def __unicode__(self):
373 return u"%s - %s" % (self.chercheur, self.groupe)
fdcf5874
EMS
374
375class ChercheurSearch(Search):
376 nom_chercheur = models.CharField(max_length=100, blank=True, verbose_name='nom')
377 domaine = models.ForeignKey(Groupe, blank=True, null=True, verbose_name='domaine de recherche')
378 groupe_recherche = models.CharField(max_length=100, blank=True, null=True,
379 verbose_name='groupe de recherche',
380 help_text='ou Laboratoire, ou Groupement inter-universitaire')
381 statut = models.CharField(max_length=100, blank=True, choices=STATUT_CHOICES + (('expert', 'Expert'),))
382 pays = models.ForeignKey(Pays, blank=True, null=True)
383 nord_sud = models.CharField(max_length=4, blank=True, choices=(('Nord', 'Nord'), ('Sud', 'Sud')),
384 verbose_name='Nord/Sud',
385 help_text="Distinction d'ordre géopolitique et économique, non géographique, qui conditionne souvent l'attribution de soutiens par les agences internationales: on entend par Nord les pays développés, par Sud les pays en développement (pays les moins avancés, pays émergents et pays à économies en transition)")
386 activites_francophonie = models.CharField(
387 max_length=25, blank=True, verbose_name='activités en Francophonie',
388 choices=(('instance_auf', "Membre d'une instance de l'AUF"),
389 ('expert_oif', "Sollicité par l'OIF"),
390 ('association_francophone', "Membre d'une association ou d'une société savante francophone"),
391 ('reseau_institutionnel', "Membre des instances d'un réseau institutionnel de l'AUF"))
392 )
393 genre = models.CharField(max_length=1, blank=True, choices=GENRE_CHOICES)
394
395 class Meta:
396 verbose_name = 'recherche de chercheurs'
397 verbose_name_plural = 'recherches de chercheurs'
398
399 def run(self):
400 results = Chercheur.objects
401 if self.q:
402 results = results.search(self.q)
403 if self.nom_chercheur:
404 results = results.add_to_query('@(nom,prenom) ' + self.nom_chercheur)
405 if self.groupe_recherche:
406 results = results.add_to_query('@groupe_recherche ' + self.groupe_recherche)
407 if self.discipline:
408 results = results.filter_discipline(self.discipline)
409 if self.region:
410 results = results.filter_region(self.region)
411 if self.statut:
412 if self.statut == "expert":
413 results = results.filter_expert()
414 else:
415 results = results.filter_statut(self.statut)
416 if self.domaine:
417 results = results.filter_groupe(self.domaine)
418 if self.pays:
419 results = results.filter_pays(self.pays)
420 if self.nord_sud:
421 results = results.filter_nord_sud(self.nord_sud)
422 if self.genre:
423 results = results.filter_genre(self.genre)
424 if self.activites_francophonie == 'instance_auf':
425 results = results.filter(membre_instance_auf=True)
426 elif self.activites_francophonie == 'expert_oif':
427 results = results.filter(expert_oif=True)
428 elif self.activites_francophonie == 'association_francophone':
429 results = results.filter(membre_association_francophone=True)
430 elif self.activites_francophonie == 'reseau_institutionnel':
431 results = results.filter(membre_reseau_institutionnel=True)
432 return results.all()
433
434 def url(self):
435 qs = self.query_string()
436 return url('chercheurs') + ('?' + qs if qs else '')