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