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_genre(self
, genre
):
134 return self
.get_query_set().filter_(genre
=genre
)
136 def filter_statut(self
, statut
):
137 return self
.get_query_set().filter_statut(statut
)
139 def filter_expert(self
):
140 return self
.get_query_set().filter_expert()
142 def order_by_nom(self
, direction
=''):
143 return self
.get_query_set().order_by_nom(self
, direction
=direction
)
145 def order_by_etablissement(self
, direction
=''):
146 return self
.get_query_set().order_by_etablissement(self
, direction
=direction
)
148 def order_by_pays(self
, direction
=''):
149 return self
.get_query_set().order_by_pays(self
, direction
=direction
)
152 ('enseignant', 'Enseignant-chercheur dans un établissement'),
153 ('etudiant', 'Étudiant-chercheur doctorant'),
154 ('independant', 'Chercheur indépendant docteur')
157 class Chercheur(Personne
):
158 RESEAU_INSTITUTIONNEL_CHOICES
= (
159 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
160 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
161 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
162 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
163 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
164 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
165 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
166 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
167 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
168 ('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)'),
169 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
170 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
172 INSTANCE_AUF_CHOICES
= (
173 ('CASSOC', 'Conseil associatif'),
174 ('CA', "Conseil d'administration"),
175 ('CS', 'Conseil scientifique'),
176 ('CRE', "Commission régionale d'experts")
179 nationalite
= models
.ForeignKey(Pays
, null
= True, db_column
='nationalite', to_field
='code',
180 verbose_name
= 'nationalité', related_name
='nationalite')
181 statut
= models
.CharField(max_length
=36, choices
=STATUT_CHOICES
)
182 diplome
= models
.CharField(max_length
=255, null
=True, verbose_name
= 'diplôme le plus élevé')
183 etablissement
= models
.ForeignKey(Etablissement
, db_column
='etablissement', null
=True, blank
=True)
184 etablissement_autre_nom
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'autre établissement')
185 etablissement_autre_pays
= models
.ForeignKey(Pays
, null
= True, blank
=True, db_column
='etablissement_autre_pays',
186 to_field
='code', related_name
='etablissement_autre_pays',
187 verbose_name
= "pays de l'établissement")
188 attestation
= models
.BooleanField()
191 thematique
= models
.ForeignKey(Thematique
, db_column
='thematique', null
=True, verbose_name
='thematique')
192 mots_cles
= models
.CharField(max_length
=255, null
=True, verbose_name
='mots-clés')
193 discipline
= models
.ForeignKey(Discipline
, db_column
='discipline', null
=True, verbose_name
='Discipline')
194 theme_recherche
= models
.TextField(null
=True, blank
=True, verbose_name
='thèmes de recherche')
195 groupe_recherche
= models
.CharField(max_length
=255, blank
=True, verbose_name
='groupe de recherche')
196 url_site_web
= models
.URLField(max_length
=255, null
=True, blank
=True,
197 verbose_name
='adresse site Internet', verify_exists
=False)
198 url_blog
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='blog',
200 url_reseau_social
= models
.URLField(
201 max_length
=255, null
=True, blank
=True, verbose_name
='Réseau social',
203 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, ...)"
206 groupes
= models
.ManyToManyField('Groupe', through
='ChercheurGroupe', blank
=True, verbose_name
='Domaines de recherche')
208 # Activités en francophonie
209 membre_instance_auf
= models
.NullBooleanField(verbose_name
="est ou a déjà été membre d'une instance de l'AUF")
210 membre_instance_auf_nom
= models
.CharField(max_length
=10, blank
=True, choices
=INSTANCE_AUF_CHOICES
, verbose_name
="instance")
211 membre_instance_auf_fonction
= models
.CharField(max_length
=255, blank
=True, verbose_name
="fonction")
212 membre_instance_auf_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
213 expert_oif
= models
.NullBooleanField(verbose_name
="a été sollicité par l'OIF")
214 expert_oif_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="détails")
215 expert_oif_dates
= models
.CharField(max_length
=255, blank
=True, verbose_name
="dates")
216 membre_association_francophone
= models
.NullBooleanField(verbose_name
="est membre d'une association francophone")
217 membre_association_francophone_details
= models
.CharField(max_length
=255, blank
=True, verbose_name
="nom de l'association")
218 membre_reseau_institutionnel
= models
.NullBooleanField(
219 verbose_name
="est membre des instances d'un réseau institutionnel de l'AUF"
221 membre_reseau_institutionnel_nom
= models
.CharField(
222 max_length
=15, choices
=RESEAU_INSTITUTIONNEL_CHOICES
, blank
=True,
223 verbose_name
="réseau institutionnel"
225 membre_reseau_institutionnel_fonction
= models
.CharField(
226 max_length
=255, blank
=True, verbose_name
="fonction"
228 membre_reseau_institutionnel_dates
= models
.CharField(
229 max_length
=255, blank
=True, verbose_name
="dates"
233 expertises_auf
= models
.NullBooleanField(verbose_name
="est disposé à réaliser des expertises pour l'AUF")
236 date_creation
= models
.DateField(auto_now_add
=True, db_column
='date_creation')
237 date_modification
= models
.DateField(auto_now
=True, db_column
='date_modification')
240 objects
= ChercheurManager()
241 all_objects
= models
.Manager()
243 def __unicode__(self
):
244 return u
"%s %s" % (self
.nom
.upper(), self
.prenom
.title())
246 def statut_display(self
):
247 for s
in STATUT_CHOICES
:
248 if self
.statut
== s
[0]:
253 def etablissement_display(self
):
254 if self
.etablissement
:
255 return self
.etablissement
.nom
+ ', ' + self
.etablissement
.pays
.nom
257 return self
.etablissement_autre_nom
+ ', ' + self
.etablissement_autre_pays
.nom
261 return self
.etablissement
.pays
if self
.etablissement
else self
.etablissement_autre_pays
265 return self
.pays
.region
268 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
269 if self
.etablissement
:
270 self
.etablissement_autre_nom
= None
271 self
.etablissement_autre_pays
= None
272 super(Chercheur
, self
).save()
274 def activation_token(self
):
275 return sha_constructor(settings
.SECRET_KEY
+ unicode(self
.id)).hexdigest()[::2]
277 class Publication(models
.Model
):
278 chercheur
= models
.ForeignKey(Chercheur
, related_name
='publications')
279 auteurs
= models
.CharField(max_length
=255, blank
=True, verbose_name
='auteur(s)')
280 titre
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='titre')
281 revue
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='revue')
282 annee
= models
.IntegerField(null
=True, blank
=True, verbose_name
='année de publication')
283 editeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='éditeur')
284 lieu_edition
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
="lieu d'édition")
285 nb_pages
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
='nombre de pages')
286 url
= models
.URLField(max_length
=255, null
=True, blank
=True, verbose_name
='lien vers la publication', verify_exists
=False)
287 #Migration des publications depuis l'ancien repertoire de chercheurs
288 publication_affichage
= models
.TextField(verbose_name
='publication', null
=True, blank
=True)
289 actif
= models
.BooleanField(editable
=False)
291 def __unicode__(self
):
292 return self
.titre
or '(Aucun)'
295 if self
.publication_affichage
and (self
.auteurs
or self
.titre
or
296 self
.revue
or self
.annee
or
297 self
.editeur
or self
.lieu_edition
298 or self
.nb_pages
or self
.url
):
299 self
.publication_affichage
= ''
300 super(Publication
, self
).save()
302 class These(models
.Model
):
303 chercheur
= models
.OneToOneField(Chercheur
, primary_key
=True)
304 titre
= models
.CharField(max_length
=255, verbose_name
='Titre')
305 annee
= models
.IntegerField(verbose_name
='Année de soutenance (réalisée ou prévue)')
306 directeur
= models
.CharField(max_length
=255, verbose_name
='Directeur')
307 etablissement
= models
.CharField(max_length
=255, verbose_name
='Établissement de soutenance')
308 nb_pages
= models
.IntegerField(verbose_name
='Nombre de pages', blank
=True, null
=True)
309 url
= models
.URLField(max_length
=255, verbose_name
='Lien vers la publication', blank
=True, verify_exists
=False)
311 def __unicode__(self
):
314 class Expertise(models
.Model
):
315 id = models
.AutoField(primary_key
=True, db_column
='id')
316 chercheur
= models
.ForeignKey(Chercheur
, related_name
='expertises')
317 nom
= models
.CharField(max_length
=255, verbose_name
= "Objet de l'expertise")
318 date
= models
.CharField(max_length
=255, blank
=True)
319 lieu
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= "Lieu de l'expertise")
320 organisme_demandeur
= models
.CharField(max_length
=255, null
=True, blank
=True, verbose_name
= 'Organisme demandeur')
321 organisme_demandeur_visible
= models
.BooleanField(verbose_name
="Afficher l'organisme demandeur")
322 actif
= models
.BooleanField(editable
= False, db_column
='actif')
324 def __unicode__(self
):
325 return u
"%s" % (self
.nom
)
327 class Groupe(models
.Model
):
328 id = models
.AutoField(primary_key
=True, db_column
='id')
329 nom
= models
.CharField(max_length
=255, db_column
='nom')
330 url
= models
.URLField(max_length
=255, null
=True, blank
=True,
331 verbose_name
='Site web')
332 liste_diffusion
= models
.URLField(max_length
=255, null
=True, blank
=True,
333 verbose_name
='Liste de diffusion')
334 bulletin
= models
.URLField(max_length
=255, null
=True, blank
=True,
335 verbose_name
='Bulletin')
336 actif
= models
.BooleanField(editable
= False, db_column
='actif')
339 verbose_name
= 'domaine de recherche'
340 verbose_name_plural
= 'domaines de recherche'
342 def __unicode__(self
):
343 return u
"%s" % (self
.nom
)
345 class ChercheurGroupe(models
.Model
):
346 id = models
.AutoField(primary_key
=True, db_column
='id')
347 chercheur
= models
.ForeignKey('Chercheur', db_column
='chercheur', editable
=False)
348 groupe
= models
.ForeignKey('Groupe', db_column
='groupe')
349 date_inscription
= models
.DateField(auto_now_add
=True)
350 date_modification
= models
.DateField(auto_now
=True)
351 actif
= models
.BooleanField(editable
= False, db_column
='actif')
354 verbose_name
= 'adhésion'
356 def __unicode__(self
):
357 return u
"%s - %s" % (self
.chercheur
, self
.groupe
)