1 # -*- encoding: utf-8 -*-
3 from datamaster_modeles
.models
import *
4 from django
.conf
import settings
5 from django
.db
import models
6 from django
.db
.models
import Q
7 from django
.utils
.encoding
import smart_str
8 from django
.utils
.hashcompat
import sha_constructor
9 from djangosphinx
.models
import SphinxSearch
10 from savoirs
.models
import Discipline
, SEPManager
, SEPSphinxQuerySet
, SEPQuerySet
12 GENRE_CHOICES
= (('m', 'Homme'), ('f', 'Femme'))
13 class Personne(models
.Model
):
14 salutation
= models
.CharField(max_length
=128, null
=True, blank
=True)
15 nom
= models
.CharField(max_length
=255)
16 prenom
= models
.CharField(max_length
=128, verbose_name
='prénom')
17 courriel
= models
.EmailField(max_length
=128, verbose_name
="adresse électronique")
18 fonction
= models
.CharField(max_length
=128, null
=True, blank
=True)
19 date_naissance
= models
.DateField(null
=True, blank
=True)
20 sousfonction
= models
.CharField(max_length
=128, null
=True, blank
=True, verbose_name
='sous-fonction')
21 mobile
= models
.CharField(max_length
=32, null
=True, blank
=True, verbose_name
='numéro de téléphone portable')
22 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
23 commentaire
= models
.TextField(verbose_name
='commentaires', null
=True, blank
=True)
24 actif
= models
.BooleanField(editable
=False, default
=True)
26 def __unicode__(self
):
27 return u
"%s %s, %s" % (self
.prenom
, self
.nom
, self
.courriel
)
30 ordering
= ["nom", "prenom"]
36 elif self
.genre
== 'f':
41 class ChercheurQuerySet(SEPQuerySet
):
43 def filter_groupe(self
, groupe
):
44 return self
.filter(groupes
=groupe
)
46 def filter_pays(self
, pays
):
47 return self
.filter(Q(etablissement__pays
=pays
) |
Q(etablissement_autre_pays
=pays
))
49 def filter_region(self
, region
):
50 return self
.filter(Q(etablissement__pays__region
=region
) |
Q(etablissement_autre_pays__region
=region
))
52 def filter_nord_sud(self
, nord_sud
):
53 return self
.filter(Q(etablissement__pays__nord_sud
=nord_sud
) |
Q(etablissement_autre_pays__nord_sud
=nord_sud
))
55 def filter_genre(self
, genre
):
56 return self
.filter(genre
=genre
)
58 def filter_statut(self
, statut
):
59 return self
.filter(statut
=statut
)
61 def filter_expert(self
):
62 return self
.exclude(expertises
=None)
64 def order_by_nom(self
, direction
=''):
65 return self
.order_by(direction
+ 'nom', direction
+ 'prenom', '-date_modification')
67 def order_by_etablissement(self
, direction
=''):
68 return self
.extra(select
=dict(nom_etablissement
='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
69 order_by
=[direction
+ 'nom_etablissement', '-date_modification'])
71 def order_by_pays(self
, direction
=''):
72 return self
.extra(select
=dict(
73 pays_etablissement
='''(SELECT nom FROM ref_pays
74 WHERE ref_pays.code = IFNULL(ref_etablissement.pays, chercheurs_chercheur.etablissement_autre_pays))'''
75 ), order_by
=[direction
+ 'pays_etablissement', '-date_modification'])
77 class ChercheurSphinxQuerySet(SEPSphinxQuerySet
):
79 def __init__(self
, model
=None):
80 return SEPSphinxQuerySet
.__init__(self
, model
=model
, index
='savoirsenpartage_chercheurs',
81 weights
=dict(nom
=2, prenom
=2))
83 def filter_region(self
, region
):
84 return self
.filter(region_id
=region
.id)
86 def filter_groupe(self
, groupe
):
87 return self
.filter(groupe_ids
=groupe
.id)
89 def filter_pays(self
, pays
):
90 return self
.filter(pays_id
=pays
.id)
92 NORD_SUD_CODES
= {'Nord': 1, 'Sud': 2}
93 def filter_nord_sud(self
, nord_sud
):
94 return self
.filter(nord_sud
=self
.NORD_SUD_CODES
[nord_sud
])
96 STATUT_CODES
= {'enseignant': 1, 'etudiant': 2, 'independant': 3}
97 def filter_statut(self
, statut
):
98 return self
.filter(statut
=self
.STATUT_CODES
[statut
])
100 def filter_expert(self
):
101 return self
.filter(expert
=True)
103 def order_by_nom(self
, direction
=''):
104 return self
.order_by(direction
+ 'nom_complet', '-date_modification')
106 def order_by_etablissement(self
, direction
=''):
107 return self
.order_by(direction
+ 'etablissement_attr', '-date_modification')
109 def order_by_pays(self
, direction
=''):
110 return self
.order_by(direction
+ 'pays_attr', '-date_modification')
112 class ChercheurManager(SEPManager
):
114 def get_query_set(self
):
115 return ChercheurQuerySet(self
.model
).filter(actif
=True)
117 def get_sphinx_query_set(self
):
118 return ChercheurSphinxQuerySet(self
.model
).order_by('-date_modification')
120 def filter_region(self
, region
):
121 """Le filtrage de chercheurs par région n'est pas une recherche texte."""
122 return self
.get_query_set().filter_region(region
)
124 def filter_groupe(self
, groupe
):
125 return self
.get_query_set().filter_groupe(groupe
)
127 def filter_pays(self
, pays
):
128 return self
.get_query_set().filter_pays(pays
)
130 def filter_nord_sud(self
, nord_sud
):
131 return self
.get_query_set().filter_nord_sud(nord_sud
)
133 def filter_statut(self
, statut
):
134 return self
.get_query_set().filter_statut(statut
)
136 def filter_expert(self
):
137 return self
.get_query_set().filter_expert()
139 def order_by_nom(self
, direction
=''):
140 return self
.get_query_set().order_by_nom(self
, direction
=direction
)
142 def order_by_etablissement(self
, direction
=''):
143 return self
.get_query_set().order_by_etablissement(self
, direction
=direction
)
145 def order_by_pays(self
, direction
=''):
146 return self
.get_query_set().order_by_pays(self
, direction
=direction
)
149 ('enseignant', 'Enseignant-chercheur dans un établissement'),
150 ('etudiant', 'Étudiant-chercheur doctorant'),
151 ('independant', 'Chercheur indépendant docteur')
154 class Chercheur(Personne
):
155 RESEAU_INSTITUTIONNEL_CHOICES
= (
156 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
157 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
158 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
159 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
160 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
161 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
162 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
163 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
164 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
165 ('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)'),
166 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
167 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
169 INSTANCE_AUF_CHOICES
= (
170 ('CASSOC', 'Conseil associatif'),
171 ('CA', "Conseil d'administration"),
172 ('CS', 'Conseil scientifique'),
173 ('CRE', "Commission régionale d'experts")
176 nationalite
= models
.ForeignKey(Pays
, null
= True, db_column
='nationalite', to_field
='code',
177 verbose_name
= 'nationalité', related_name
='nationalite')
178 statut
= models
.CharField(max_length
=36, choices
=STATUT_CHOICES
)
179 diplome
= models
.CharField(max_length
=255, null
=True, verbose_name
= 'diplôme le plus élevé')
180 etablissement
= models
.ForeignKey(Etablissement
, db_column
='etablissement', null
=True, blank
=True)
181 etablissement_autre_nom
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'autre établissement')
182 etablissement_autre_pays
= models
.ForeignKey(Pays
, null
= True, blank
=True, db_column
='etablissement_autre_pays',
183 to_field
='code', related_name
='etablissement_autre_pays',
184 verbose_name
= "pays de l'établissement")
185 attestation
= models
.BooleanField()
188 thematique
= models
.ForeignKey(Thematique
, db_column
='thematique', null
=True, verbose_name
='thematique')
189 mots_cles
= models
.CharField(max_length
=255, null
=True, verbose_name
='mots-clés')
190 discipline
= models
.ForeignKey(Discipline
, db_column
='discipline', null
=True, verbose_name
='Discipline')
191 theme_recherche
= models
.TextField(null
=True, blank
=True, verbose_name
='thèmes de recherche')
192 groupe_recherche
= models
.CharField(max_length
=255, blank
=True, verbose_name
='groupe de recherche')
193 url_site_web
= models
.URLField(max_length
=255, null
=True, blank
=True,
194 verbose_name
='adresse site Internet', verify_exists
=False)
195 url_blog
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='blog',
197 url_reseau_social
= models
.URLField(
198 max_length
=255, null
=True, blank
=True, verbose_name
='Réseau social',
200 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, ...)"
203 groupes
= models
.ManyToManyField('Groupe', through
='ChercheurGroupe', blank
=True, verbose_name
='Domaines de recherche')
205 # Activités en francophonie
206 membre_instance_auf
= models
.NullBooleanField(verbose_name
="est ou a déjà été membre d'une instance de l'AUF")
207 membre_instance_auf_nom
= models
.CharField(max_length
=10, blank
=True, choices
=INSTANCE_AUF_CHOICES
, verbose_name
="instance")
208 membre_instance_auf_fonction
= models
.CharField(max_length
=255, blank
=True, verbose_name
="fonction")
209 membre_instance_auf_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
210 expert_oif
= models
.NullBooleanField(verbose_name
="a été sollicité par l'OIF")
211 expert_oif_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="détails")
212 expert_oif_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
213 membre_association_francophone
= models
.NullBooleanField(verbose_name
="est membre d'une association francophone")
214 membre_association_francophone_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="nom de l'association")
215 membre_reseau_institutionnel
= models
.NullBooleanField(
216 verbose_name
="est membre des instances d'un réseau institutionnel de l'AUF"
218 membre_reseau_institutionnel_nom
= models
.CharField(
219 max_length
=15, choices
=RESEAU_INSTITUTIONNEL_CHOICES
, blank
=True,
220 verbose_name
="réseau institutionnel"
222 membre_reseau_institutionnel_fonction
= models
.CharField(
223 max_length
=255, blank
=True, verbose_name
="fonction"
225 membre_reseau_institutionnel_dates
= models
.CharField(
226 max_length
=255, blank
=True, verbose_name
="dates"
230 expertises_auf
= models
.NullBooleanField(verbose_name
="est disposé à réaliser des expertises pour l'AUF")
233 date_creation
= models
.DateField(auto_now_add
=True, db_column
='date_creation')
234 date_modification
= models
.DateField(auto_now
=True, db_column
='date_modification')
237 objects
= ChercheurManager()
238 all_objects
= models
.Manager()
240 def __unicode__(self
):
241 return u
"%s %s" % (self
.nom
.upper(), self
.prenom
.title())
243 def statut_display(self
):
244 for s
in STATUT_CHOICES
:
245 if self
.statut
== s
[0]:
250 def etablissement_display(self
):
251 if self
.etablissement
:
252 return self
.etablissement
.nom
+ ', ' + self
.etablissement
.pays
.nom
254 return self
.etablissement_autre_nom
+ ', ' + self
.etablissement_autre_pays
.nom
258 return self
.etablissement
.pays
if self
.etablissement
else self
.etablissement_autre_pays
262 return self
.pays
.region
265 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
266 if self
.etablissement
:
267 self
.etablissement_autre_nom
= None
268 self
.etablissement_autre_pays
= None
269 super(Chercheur
, self
).save()
271 def activation_token(self
):
272 return sha_constructor(settings
.SECRET_KEY
+ unicode(self
.id)).hexdigest()[::2]
274 class Publication(models
.Model
):
275 chercheur
= models
.ForeignKey(Chercheur
, related_name
='publications')
276 auteurs
= models
.CharField(max_length
=255, blank
=True, verbose_name
='auteur(s)')
277 titre
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='titre')
278 revue
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='revue')
279 annee
= models
.IntegerField(null
=True, blank
=True, verbose_name
='année de publication')
280 editeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='éditeur')
281 lieu_edition
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
="lieu d'édition")
282 nb_pages
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='nombre de pages')
283 url
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='lien vers la publication', verify_exists
=False)
284 #Migration des publications depuis l'ancien repertoire de chercheurs
285 publication_affichage
= models
.TextField(verbose_name
='publication', null
=True, blank
=True)
286 actif
= models
.BooleanField(editable
=False)
288 def __unicode__(self
):
289 return self
.titre
or '(Aucun)'
292 if self
.publication_affichage
and (self
.auteurs
or self
.titre
or
293 self
.revue
or self
.annee
or
294 self
.editeur
or self
.lieu_edition
295 or self
.nb_pages
or self
.url
):
296 self
.publication_affichage
= ''
297 super(Publication
, self
).save()
299 class These(models
.Model
):
300 chercheur
= models
.OneToOneField(Chercheur
, primary_key
=True)
301 titre
= models
.CharField(max_length
=255, verbose_name
='Titre')
302 annee
= models
.IntegerField(verbose_name
='Année de soutenance (réalisée ou prévue)')
303 directeur
= models
.CharField(max_length
=255, verbose_name
='Directeur')
304 etablissement
= models
.CharField(max_length
=255, verbose_name
='Établissement de soutenance')
305 nb_pages
= models
.IntegerField(verbose_name
='Nombre de pages', blank
=True, null
=True)
306 url
= models
.URLField(max_length
=255, verbose_name
='Lien vers la publication', blank
=True, verify_exists
=False)
308 def __unicode__(self
):
311 class Expertise(models
.Model
):
312 id = models
.AutoField(primary_key
=True, db_column
='id')
313 chercheur
= models
.ForeignKey(Chercheur
, related_name
='expertises')
314 nom
= models
.CharField(max_length
=255, verbose_name
= "Objet de l'expertise")
315 date
= models
.CharField(max_length
=255, blank
=True)
316 lieu
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= "Lieu de l'expertise")
317 organisme_demandeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'Organisme demandeur')
318 organisme_demandeur_visible
= models
.BooleanField(verbose_name
="Afficher l'organisme demandeur")
319 actif
= models
.BooleanField(editable
= False, db_column
='actif')
321 def __unicode__(self
):
322 return u
"%s" % (self
.nom
)
324 class Groupe(models
.Model
):
325 id = models
.AutoField(primary_key
=True, db_column
='id')
326 nom
= models
.CharField(max_length
=255, db_column
='nom')
327 url
= models
.URLField(max_length
=255, null
=True, blank
=True,
328 verbose_name
='Site web')
329 liste_diffusion
= models
.URLField(max_length
=255, null
=True, blank
=True,
330 verbose_name
='Liste de diffusion')
331 bulletin
= models
.URLField(max_length
=255, null
=True, blank
=True,
332 verbose_name
='Bulletin')
333 actif
= models
.BooleanField(editable
= False, db_column
='actif')
336 verbose_name
= 'domaine de recherche'
337 verbose_name_plural
= 'domaines de recherche'
339 def __unicode__(self
):
340 return u
"%s" % (self
.nom
)
342 class ChercheurGroupe(models
.Model
):
343 id = models
.AutoField(primary_key
=True, db_column
='id')
344 chercheur
= models
.ForeignKey('Chercheur', db_column
='chercheur', editable
=False)
345 groupe
= models
.ForeignKey('Groupe', db_column
='groupe')
346 date_inscription
= models
.DateField(auto_now_add
=True)
347 date_modification
= models
.DateField(auto_now
=True)
348 actif
= models
.BooleanField(editable
= False, db_column
='actif')
351 verbose_name
= 'adhésion'
353 def __unicode__(self
):
354 return u
"%s - %s" % (self
.chercheur
, self
.groupe
)