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
="courriel")
18 afficher_courriel
= models
.BooleanField(default
=True)
19 fonction
= models
.CharField(max_length
=128, null
=True, blank
=True)
20 date_naissance
= models
.DateField(null
=True, blank
=True)
21 sousfonction
= models
.CharField(max_length
=128, null
=True, blank
=True, verbose_name
='sous-fonction')
22 telephone
= models
.CharField(max_length
=32, null
=True, blank
=True, verbose_name
='numéro de téléphone')
23 adresse_postale
= models
.TextField(blank
=True)
24 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
25 commentaire
= models
.TextField(verbose_name
='commentaires', null
=True, blank
=True)
26 actif
= models
.BooleanField(editable
=False, default
=True)
28 def __unicode__(self
):
29 return u
"%s %s, %s" % (self
.prenom
, self
.nom
, self
.courriel
)
32 ordering
= ["nom", "prenom"]
38 elif self
.genre
== 'f':
43 def courriel_display(self
):
44 return self
.courriel
.replace(u
'@', u
' (à) ')
46 class ChercheurQuerySet(SEPQuerySet
):
48 def filter_groupe(self
, groupe
):
49 return self
.filter(groupes
=groupe
)
51 def filter_pays(self
, pays
):
52 return self
.filter(Q(etablissement__pays
=pays
) |
Q(etablissement_autre_pays
=pays
))
54 def filter_region(self
, region
):
55 return self
.filter(Q(etablissement__pays__region
=region
) |
Q(etablissement_autre_pays__region
=region
))
57 def filter_nord_sud(self
, nord_sud
):
58 return self
.filter(Q(etablissement__pays__nord_sud
=nord_sud
) |
Q(etablissement_autre_pays__nord_sud
=nord_sud
))
60 def filter_genre(self
, genre
):
61 return self
.filter(genre
=genre
)
63 def filter_statut(self
, statut
):
64 return self
.filter(statut
=statut
)
66 def filter_expert(self
):
67 return self
.exclude(expertises
=None)
69 def order_by_nom(self
, direction
=''):
70 return self
.order_by(direction
+ 'nom', direction
+ 'prenom', '-date_modification')
72 def order_by_etablissement(self
, direction
=''):
73 return self
.extra(select
=dict(nom_etablissement
='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
74 order_by
=[direction
+ 'nom_etablissement', '-date_modification'])
76 def order_by_pays(self
, direction
=''):
77 return self
.extra(select
=dict(
78 pays_etablissement
='''(SELECT nom FROM ref_pays
79 WHERE ref_pays.code = IFNULL(ref_etablissement.pays, chercheurs_chercheur.etablissement_autre_pays))'''
80 ), order_by
=[direction
+ 'pays_etablissement', '-date_modification'])
82 class ChercheurSphinxQuerySet(SEPSphinxQuerySet
):
84 def __init__(self
, model
=None):
85 return SEPSphinxQuerySet
.__init__(self
, model
=model
, index
='savoirsenpartage_chercheurs',
86 weights
=dict(nom
=2, prenom
=2))
88 def filter_region(self
, region
):
89 return self
.filter(region_id
=region
.id)
91 def filter_groupe(self
, groupe
):
92 return self
.filter(groupe_ids
=groupe
.id)
94 def filter_pays(self
, pays
):
95 return self
.filter(pays_id
=pays
.id)
97 NORD_SUD_CODES
= {'Nord': 1, 'Sud': 2}
98 def filter_nord_sud(self
, nord_sud
):
99 return self
.filter(nord_sud
=self
.NORD_SUD_CODES
[nord_sud
])
101 GENRE_CODES
= dict([(k
, i
+1) for i
, (k
, v
) in enumerate(GENRE_CHOICES
)])
102 def filter_genre(self
, genre
):
103 return self
.filter(genre
=self
.GENRE_CODES
[genre
])
105 STATUT_CODES
= {'enseignant': 1, 'etudiant': 2, 'independant': 3}
106 def filter_statut(self
, statut
):
107 return self
.filter(statut
=self
.STATUT_CODES
[statut
])
109 def filter_expert(self
):
110 return self
.filter(expert
=True)
112 def order_by_nom(self
, direction
=''):
113 return self
.order_by(direction
+ 'nom_complet', '-date_modification')
115 def order_by_etablissement(self
, direction
=''):
116 return self
.order_by(direction
+ 'etablissement_attr', '-date_modification')
118 def order_by_pays(self
, direction
=''):
119 return self
.order_by(direction
+ 'pays_attr', '-date_modification')
121 class ChercheurManager(SEPManager
):
123 def get_query_set(self
):
124 return ChercheurQuerySet(self
.model
).filter(actif
=True)
126 def get_sphinx_query_set(self
):
127 return ChercheurSphinxQuerySet(self
.model
).order_by('-date_modification')
129 def filter_region(self
, region
):
130 """Le filtrage de chercheurs par région n'est pas une recherche texte."""
131 return self
.get_query_set().filter_region(region
)
133 def filter_groupe(self
, groupe
):
134 return self
.get_query_set().filter_groupe(groupe
)
136 def filter_pays(self
, pays
):
137 return self
.get_query_set().filter_pays(pays
)
139 def filter_nord_sud(self
, nord_sud
):
140 return self
.get_query_set().filter_nord_sud(nord_sud
)
142 def filter_genre(self
, genre
):
143 return self
.get_query_set().filter_genre(genre
=genre
)
145 def filter_statut(self
, statut
):
146 return self
.get_query_set().filter_statut(statut
)
148 def filter_expert(self
):
149 return self
.get_query_set().filter_expert()
151 def order_by_nom(self
, direction
=''):
152 return self
.get_query_set().order_by_nom(self
, direction
=direction
)
154 def order_by_etablissement(self
, direction
=''):
155 return self
.get_query_set().order_by_etablissement(self
, direction
=direction
)
157 def order_by_pays(self
, direction
=''):
158 return self
.get_query_set().order_by_pays(self
, direction
=direction
)
161 ('enseignant', 'Enseignant-chercheur dans un établissement'),
162 ('etudiant', 'Étudiant-chercheur doctorant'),
163 ('independant', 'Chercheur indépendant docteur')
166 class Chercheur(Personne
):
167 RESEAU_INSTITUTIONNEL_CHOICES
= (
168 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
169 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
170 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
171 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
172 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
173 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
174 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
175 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
176 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
177 ('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)'),
178 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
179 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
181 INSTANCE_AUF_CHOICES
= (
182 ('CASSOC', 'Conseil associatif'),
183 ('CA', "Conseil d'administration"),
184 ('CS', 'Conseil scientifique'),
185 ('CRE', "Commission régionale d'experts"),
186 ('CR', 'Conférence des recteurs'),
187 ('CNO', "Conseil national d'orientation")
190 nationalite
= models
.ForeignKey(Pays
, null
= True, db_column
='nationalite', to_field
='code',
191 verbose_name
= 'nationalité', related_name
='nationalite')
192 statut
= models
.CharField(max_length
=36, choices
=STATUT_CHOICES
)
193 diplome
= models
.CharField(max_length
=255, null
=True, verbose_name
= 'diplôme le plus élevé')
194 etablissement
= models
.ForeignKey(Etablissement
, db_column
='etablissement', null
=True, blank
=True)
195 etablissement_autre_nom
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'autre établissement')
196 etablissement_autre_pays
= models
.ForeignKey(Pays
, null
= True, blank
=True, db_column
='etablissement_autre_pays',
197 to_field
='code', related_name
='etablissement_autre_pays',
198 verbose_name
= "pays de l'établissement")
199 attestation
= models
.BooleanField()
202 thematique
= models
.ForeignKey(Thematique
, db_column
='thematique', null
=True, verbose_name
='thematique')
203 mots_cles
= models
.CharField(max_length
=255, null
=True, verbose_name
='mots-clés')
204 discipline
= models
.ForeignKey(Discipline
, db_column
='discipline', null
=True, verbose_name
='Discipline')
205 theme_recherche
= models
.TextField(null
=True, blank
=True, verbose_name
='thèmes de recherche')
206 groupe_recherche
= models
.CharField(max_length
=255, blank
=True, verbose_name
='groupe de recherche')
207 url_site_web
= models
.URLField(max_length
=255, null
=True, blank
=True,
208 verbose_name
='adresse site Internet', verify_exists
=False)
209 url_blog
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='blog',
211 url_reseau_social
= models
.URLField(
212 max_length
=255, null
=True, blank
=True, verbose_name
='Réseau social',
214 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, ...)"
217 groupes
= models
.ManyToManyField('Groupe', through
='ChercheurGroupe', blank
=True, verbose_name
='Domaines de recherche')
219 # Activités en francophonie
220 membre_instance_auf
= models
.NullBooleanField(verbose_name
="est ou a déjà été membre d'une instance de l'AUF")
221 membre_instance_auf_nom
= models
.CharField(max_length
=10, blank
=True, choices
=INSTANCE_AUF_CHOICES
, verbose_name
="instance")
222 membre_instance_auf_fonction
= models
.CharField(max_length
=255, blank
=True, verbose_name
="fonction")
223 membre_instance_auf_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
224 expert_oif
= models
.NullBooleanField(verbose_name
="a été sollicité par l'OIF")
225 expert_oif_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="détails")
226 expert_oif_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
227 membre_association_francophone
= models
.NullBooleanField(verbose_name
="est membre d'une association francophone")
228 membre_association_francophone_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="nom de l'association")
229 membre_reseau_institutionnel
= models
.NullBooleanField(
230 verbose_name
="est membre des instances d'un réseau institutionnel de l'AUF"
232 membre_reseau_institutionnel_nom
= models
.CharField(
233 max_length
=15, choices
=RESEAU_INSTITUTIONNEL_CHOICES
, blank
=True,
234 verbose_name
="réseau institutionnel"
236 membre_reseau_institutionnel_fonction
= models
.CharField(
237 max_length
=255, blank
=True, verbose_name
="fonction"
239 membre_reseau_institutionnel_dates
= models
.CharField(
240 max_length
=255, blank
=True, verbose_name
="dates"
244 expertises_auf
= models
.NullBooleanField(verbose_name
="est disposé à réaliser des expertises pour l'AUF")
247 date_creation
= models
.DateField(auto_now_add
=True, db_column
='date_creation')
248 date_modification
= models
.DateField(auto_now
=True, db_column
='date_modification')
251 objects
= ChercheurManager()
252 all_objects
= models
.Manager()
254 def __unicode__(self
):
255 return u
"%s %s" % (self
.nom
.upper(), self
.prenom
.title())
257 def statut_display(self
):
258 for s
in STATUT_CHOICES
:
259 if self
.statut
== s
[0]:
264 def etablissement_display(self
):
265 if self
.etablissement
:
266 return self
.etablissement
.nom
+ ', ' + self
.etablissement
.pays
.nom
268 return self
.etablissement_autre_nom
+ ', ' + self
.etablissement_autre_pays
.nom
272 return self
.etablissement
.pays
if self
.etablissement
else self
.etablissement_autre_pays
276 return self
.pays
.region
279 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
280 if self
.etablissement
:
281 self
.etablissement_autre_nom
= None
282 self
.etablissement_autre_pays
= None
283 super(Chercheur
, self
).save()
285 def activation_token(self
):
286 return sha_constructor(settings
.SECRET_KEY
+ unicode(self
.id)).hexdigest()[::2]
288 class Publication(models
.Model
):
289 chercheur
= models
.ForeignKey(Chercheur
, related_name
='publications')
290 auteurs
= models
.CharField(max_length
=255, blank
=True, verbose_name
='auteur(s)')
291 titre
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='titre')
292 revue
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='revue')
293 annee
= models
.IntegerField(null
=True, blank
=True, verbose_name
='année de publication')
294 editeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='éditeur')
295 lieu_edition
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
="lieu d'édition")
296 nb_pages
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='nombre de pages')
297 url
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='lien vers la publication', verify_exists
=False)
298 #Migration des publications depuis l'ancien repertoire de chercheurs
299 publication_affichage
= models
.TextField(verbose_name
='publication', null
=True, blank
=True)
300 actif
= models
.BooleanField(editable
=False)
302 def __unicode__(self
):
303 return self
.titre
or '(Aucun)'
306 if self
.publication_affichage
and (self
.auteurs
or self
.titre
or
307 self
.revue
or self
.annee
or
308 self
.editeur
or self
.lieu_edition
309 or self
.nb_pages
or self
.url
):
310 self
.publication_affichage
= ''
311 super(Publication
, self
).save()
313 class These(models
.Model
):
314 chercheur
= models
.OneToOneField(Chercheur
, primary_key
=True)
315 titre
= models
.CharField(max_length
=255, verbose_name
='Titre')
316 annee
= models
.IntegerField(verbose_name
='Année de soutenance (réalisée ou prévue)')
317 directeur
= models
.CharField(max_length
=255, verbose_name
='Directeur')
318 etablissement
= models
.CharField(max_length
=255, verbose_name
='Établissement de soutenance')
319 nb_pages
= models
.IntegerField(verbose_name
='Nombre de pages', blank
=True, null
=True)
320 url
= models
.URLField(max_length
=255, verbose_name
='Lien vers la publication', blank
=True, verify_exists
=False)
322 def __unicode__(self
):
325 class Expertise(models
.Model
):
326 id = models
.AutoField(primary_key
=True, db_column
='id')
327 chercheur
= models
.ForeignKey(Chercheur
, related_name
='expertises')
328 nom
= models
.CharField(max_length
=255, verbose_name
= "Objet de l'expertise")
329 date
= models
.CharField(max_length
=255, blank
=True)
330 lieu
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= "Lieu de l'expertise")
331 organisme_demandeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'Organisme demandeur')
332 organisme_demandeur_visible
= models
.BooleanField(verbose_name
="Afficher l'organisme demandeur")
333 actif
= models
.BooleanField(editable
= False, db_column
='actif')
335 def __unicode__(self
):
336 return u
"%s" % (self
.nom
)
338 class Groupe(models
.Model
):
339 id = models
.AutoField(primary_key
=True, db_column
='id')
340 nom
= models
.CharField(max_length
=255, db_column
='nom')
341 url
= models
.URLField(max_length
=255, null
=True, blank
=True,
342 verbose_name
='Site web')
343 liste_diffusion
= models
.URLField(max_length
=255, null
=True, blank
=True,
344 verbose_name
='Liste de diffusion')
345 bulletin
= models
.URLField(max_length
=255, null
=True, blank
=True,
346 verbose_name
='Bulletin')
347 actif
= models
.BooleanField(editable
= False, db_column
='actif')
350 verbose_name
= 'domaine de recherche'
351 verbose_name_plural
= 'domaines de recherche'
353 def __unicode__(self
):
354 return u
"%s" % (self
.nom
)
356 class ChercheurGroupe(models
.Model
):
357 id = models
.AutoField(primary_key
=True, db_column
='id')
358 chercheur
= models
.ForeignKey('Chercheur', db_column
='chercheur', editable
=False)
359 groupe
= models
.ForeignKey('Groupe', db_column
='groupe')
360 date_inscription
= models
.DateField(auto_now_add
=True)
361 date_modification
= models
.DateField(auto_now
=True)
362 actif
= models
.BooleanField(editable
= False, db_column
='actif')
365 verbose_name
= 'adhésion'
367 def __unicode__(self
):
368 return u
"%s - %s" % (self
.chercheur
, self
.groupe
)