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_statut(self
, statut
):
56 return self
.filter(statut
=statut
)
58 def filter_expert(self
):
59 return self
.exclude(expertises
=None)
61 def order_by_nom(self
, direction
=''):
62 return self
.order_by(direction
+ 'nom', direction
+ 'prenom', '-date_modification')
64 def order_by_etablissement(self
, direction
=''):
65 return self
.extra(select
=dict(nom_etablissement
='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
66 order_by
=[direction
+ 'nom_etablissement', '-date_modification'])
68 def order_by_pays(self
, direction
=''):
69 return self
.extra(select
=dict(
70 pays_etablissement
='''(SELECT nom FROM ref_pays
71 WHERE ref_pays.code = IFNULL(ref_etablissement.pays, chercheurs_chercheur.etablissement_autre_pays))'''
72 ), order_by
=[direction
+ 'pays_etablissement', '-date_modification'])
74 class ChercheurSphinxQuerySet(SEPSphinxQuerySet
):
76 def __init__(self
, model
=None):
77 return SEPSphinxQuerySet
.__init__(self
, model
=model
, index
='savoirsenpartage_chercheurs',
78 weights
=dict(nom
=2, prenom
=2))
80 def filter_region(self
, region
):
81 return self
.filter(region_id
=region
.id)
83 def filter_groupe(self
, groupe
):
84 return self
.filter(groupe_ids
=groupe
.id)
86 def filter_pays(self
, pays
):
87 return self
.filter(pays_id
=pays
.id)
89 NORD_SUD_CODES
= {'Nord': 1, 'Sud': 2}
90 def filter_nord_sud(self
, nord_sud
):
91 return self
.filter(nord_sud
=self
.NORD_SUD_CODES
[nord_sud
])
93 STATUT_CODES
= {'enseignant': 1, 'etudiant': 2, 'independant': 3}
94 def filter_statut(self
, statut
):
95 return self
.filter(statut
=self
.STATUT_CODES
[statut
])
97 def filter_expert(self
):
98 return self
.filter(expert
=True)
100 def order_by_nom(self
, direction
=''):
101 return self
.order_by(direction
+ 'nom_complet', '-date_modification')
103 def order_by_etablissement(self
, direction
=''):
104 return self
.order_by(direction
+ 'etablissement_attr', '-date_modification')
106 def order_by_pays(self
, direction
=''):
107 return self
.order_by(direction
+ 'pays_attr', '-date_modification')
109 class ChercheurManager(SEPManager
):
111 def get_query_set(self
):
112 return ChercheurQuerySet(self
.model
).filter(actif
=True)
114 def get_sphinx_query_set(self
):
115 return ChercheurSphinxQuerySet(self
.model
).order_by('-date_modification')
117 def filter_region(self
, region
):
118 """Le filtrage de chercheurs par région n'est pas une recherche texte."""
119 return self
.get_query_set().filter_region(region
)
121 def filter_groupe(self
, groupe
):
122 return self
.get_query_set().filter_groupe(groupe
)
124 def filter_pays(self
, pays
):
125 return self
.get_query_set().filter_pays(pays
)
127 def filter_nord_sud(self
, nord_sud
):
128 return self
.get_query_set().filter_nord_sud(nord_sud
)
130 def filter_statut(self
, statut
):
131 return self
.get_query_set().filter_statut(statut
)
133 def filter_expert(self
):
134 return self
.get_query_set().filter_expert()
136 def order_by_nom(self
, direction
=''):
137 return self
.get_query_set().order_by_nom(self
, direction
=direction
)
139 def order_by_etablissement(self
, direction
=''):
140 return self
.get_query_set().order_by_etablissement(self
, direction
=direction
)
142 def order_by_pays(self
, direction
=''):
143 return self
.get_query_set().order_by_pays(self
, direction
=direction
)
146 ('enseignant', 'Enseignant-chercheur dans un établissement'),
147 ('etudiant', 'Étudiant-chercheur doctorant'),
148 ('independant', 'Chercheur indépendant docteur')
151 class Chercheur(Personne
):
152 RESEAU_INSTITUTIONNEL_CHOICES
= (
153 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
154 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
155 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
156 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
157 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
158 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
159 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
160 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
161 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
162 ('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)'),
163 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
164 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
166 INSTANCE_AUF_CHOICES
= (
167 ('CASSOC', 'Conseil associatif'),
168 ('CA', "Conseil d'administration"),
169 ('CS', 'Conseil scientifique'),
170 ('CRE', "Commission régionale d'experts")
173 nationalite
= models
.ForeignKey(Pays
, null
= True, db_column
='nationalite', to_field
='code',
174 verbose_name
= 'nationalité', related_name
='nationalite')
175 statut
= models
.CharField(max_length
=36, choices
=STATUT_CHOICES
)
176 diplome
= models
.CharField(max_length
=255, null
=True, verbose_name
= 'diplôme le plus élevé')
177 etablissement
= models
.ForeignKey(Etablissement
, db_column
='etablissement', null
=True, blank
=True)
178 etablissement_autre_nom
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'autre établissement')
179 etablissement_autre_pays
= models
.ForeignKey(Pays
, null
= True, blank
=True, db_column
='etablissement_autre_pays',
180 to_field
='code', related_name
='etablissement_autre_pays',
181 verbose_name
= "pays de l'établissement")
182 attestation
= models
.BooleanField()
185 thematique
= models
.ForeignKey(Thematique
, db_column
='thematique', null
=True, verbose_name
='thematique')
186 mots_cles
= models
.CharField(max_length
=255, null
=True, verbose_name
='mots-clés')
187 discipline
= models
.ForeignKey(Discipline
, db_column
='discipline', null
=True, verbose_name
='Discipline')
188 theme_recherche
= models
.TextField(null
=True, blank
=True, verbose_name
='thèmes de recherche')
189 groupe_recherche
= models
.CharField(max_length
=255, blank
=True, verbose_name
='groupe de recherche')
190 url_site_web
= models
.URLField(max_length
=255, null
=True, blank
=True,
191 verbose_name
='adresse site Internet', verify_exists
=False)
192 url_blog
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='blog',
194 url_reseau_social
= models
.URLField(
195 max_length
=255, null
=True, blank
=True, verbose_name
='Réseau social',
197 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, ...)"
200 groupes
= models
.ManyToManyField('Groupe', through
='ChercheurGroupe', blank
=True, verbose_name
='Domaines de recherche')
202 # Activités en francophonie
203 membre_instance_auf
= models
.NullBooleanField(verbose_name
="est ou a déjà été membre d'une instance de l'AUF")
204 membre_instance_auf_nom
= models
.CharField(max_length
=10, blank
=True, choices
=INSTANCE_AUF_CHOICES
, verbose_name
="instance")
205 membre_instance_auf_fonction
= models
.CharField(max_length
=255, blank
=True, verbose_name
="fonction")
206 membre_instance_auf_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
207 expert_oif
= models
.NullBooleanField(verbose_name
="a été sollicité par l'OIF")
208 expert_oif_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="détails")
209 expert_oif_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
210 membre_association_francophone
= models
.NullBooleanField(verbose_name
="est membre d'une association francophone")
211 membre_association_francophone_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="nom de l'association")
212 membre_reseau_institutionnel
= models
.NullBooleanField(
213 verbose_name
="est membre des instances d'un réseau institutionnel de l'AUF"
215 membre_reseau_institutionnel_nom
= models
.CharField(
216 max_length
=15, choices
=RESEAU_INSTITUTIONNEL_CHOICES
, blank
=True,
217 verbose_name
="réseau institutionnel"
219 membre_reseau_institutionnel_fonction
= models
.CharField(
220 max_length
=255, blank
=True, verbose_name
="fonction"
222 membre_reseau_institutionnel_dates
= models
.CharField(
223 max_length
=255, blank
=True, verbose_name
="dates"
227 expertises_auf
= models
.NullBooleanField(verbose_name
="est disposé à réaliser des expertises pour l'AUF")
230 date_creation
= models
.DateField(auto_now_add
=True, db_column
='date_creation')
231 date_modification
= models
.DateField(auto_now
=True, db_column
='date_modification')
234 objects
= ChercheurManager()
235 all_objects
= models
.Manager()
237 def __unicode__(self
):
238 return u
"%s %s" % (self
.nom
.upper(), self
.prenom
.title())
240 def statut_display(self
):
241 for s
in STATUT_CHOICES
:
242 if self
.statut
== s
[0]:
247 def etablissement_display(self
):
248 if self
.etablissement
:
249 return self
.etablissement
.nom
+ ', ' + self
.etablissement
.pays
.nom
251 return self
.etablissement_autre_nom
+ ', ' + self
.etablissement_autre_pays
.nom
255 return self
.etablissement
.pays
if self
.etablissement
else self
.etablissement_autre_pays
259 return self
.pays
.region
262 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
263 if self
.etablissement
:
264 self
.etablissement_autre_nom
= None
265 self
.etablissement_autre_pays
= None
266 super(Chercheur
, self
).save()
268 def activation_token(self
):
269 return sha_constructor(settings
.SECRET_KEY
+ unicode(self
.id)).hexdigest()[::2]
271 class Publication(models
.Model
):
272 chercheur
= models
.ForeignKey(Chercheur
, related_name
='publications')
273 auteurs
= models
.CharField(max_length
=255, blank
=True, verbose_name
='auteur(s)')
274 titre
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='titre')
275 revue
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='revue')
276 annee
= models
.IntegerField(null
=True, blank
=True, verbose_name
='année de publication')
277 editeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='éditeur')
278 lieu_edition
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
="lieu d'édition")
279 nb_pages
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='nombre de pages')
280 url
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='lien vers la publication', verify_exists
=False)
281 #Migration des publications depuis l'ancien repertoire de chercheurs
282 publication_affichage
= models
.TextField(verbose_name
='publication', null
=True, blank
=True)
283 actif
= models
.BooleanField(editable
=False)
285 def __unicode__(self
):
286 return self
.titre
or '(Aucun)'
289 if self
.publication_affichage
and (self
.auteurs
or self
.titre
or
290 self
.revue
or self
.annee
or
291 self
.editeur
or self
.lieu_edition
292 or self
.nb_pages
or self
.url
):
293 self
.publication_affichage
= ''
294 super(Publication
, self
).save()
296 class These(models
.Model
):
297 chercheur
= models
.OneToOneField(Chercheur
, primary_key
=True)
298 titre
= models
.CharField(max_length
=255, verbose_name
='Titre')
299 annee
= models
.IntegerField(verbose_name
='Année de soutenance (réalisée ou prévue)')
300 directeur
= models
.CharField(max_length
=255, verbose_name
='Directeur')
301 etablissement
= models
.CharField(max_length
=255, verbose_name
='Établissement de soutenance')
302 nb_pages
= models
.IntegerField(verbose_name
='Nombre de pages', blank
=True, null
=True)
303 url
= models
.URLField(max_length
=255, verbose_name
='Lien vers la publication', blank
=True, verify_exists
=False)
305 def __unicode__(self
):
308 class Expertise(models
.Model
):
309 id = models
.AutoField(primary_key
=True, db_column
='id')
310 chercheur
= models
.ForeignKey(Chercheur
, related_name
='expertises')
311 nom
= models
.CharField(max_length
=255, verbose_name
= "Objet de l'expertise")
312 date
= models
.CharField(max_length
=255, blank
=True)
313 lieu
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= "Lieu de l'expertise")
314 organisme_demandeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'Organisme demandeur')
315 organisme_demandeur_visible
= models
.BooleanField(verbose_name
="Afficher l'organisme demandeur")
316 actif
= models
.BooleanField(editable
= False, db_column
='actif')
318 def __unicode__(self
):
319 return u
"%s" % (self
.nom
)
321 class Groupe(models
.Model
):
322 id = models
.AutoField(primary_key
=True, db_column
='id')
323 nom
= models
.CharField(max_length
=255, db_column
='nom')
324 url
= models
.URLField(max_length
=255, null
=True, blank
=True,
325 verbose_name
='Site web')
326 liste_diffusion
= models
.URLField(max_length
=255, null
=True, blank
=True,
327 verbose_name
='Liste de diffusion')
328 bulletin
= models
.URLField(max_length
=255, null
=True, blank
=True,
329 verbose_name
='Bulletin')
330 actif
= models
.BooleanField(editable
= False, db_column
='actif')
333 verbose_name
= 'domaine de recherche'
334 verbose_name_plural
= 'domaines de recherche'
336 def __unicode__(self
):
337 return u
"%s" % (self
.nom
)
339 class ChercheurGroupe(models
.Model
):
340 id = models
.AutoField(primary_key
=True, db_column
='id')
341 chercheur
= models
.ForeignKey('Chercheur', db_column
='chercheur', editable
=False)
342 groupe
= models
.ForeignKey('Groupe', db_column
='groupe')
343 date_inscription
= models
.DateField(auto_now_add
=True)
344 date_modification
= models
.DateField(auto_now
=True)
345 actif
= models
.BooleanField(editable
= False, db_column
='actif')
348 verbose_name
= 'adhésion'
350 def __unicode__(self
):
351 return u
"%s - %s" % (self
.chercheur
, self
.groupe
)