1 # -*- encoding: utf-8 -*-
3 from django
import forms
4 from django
.db
.models
import Q
5 from django
.forms
.models
import inlineformset_factory
6 from itertools
import chain
9 OUI_NON_CHOICES
= (('1', 'Oui'), ('0', 'Non'))
11 class ChercheurForm(forms
.ModelForm
):
12 """Formulaire d'édition d'un chercheur."""
13 genre
= forms
.ChoiceField(widget
=forms
.RadioSelect(), choices
=GENRE_CHOICES
)
14 membre_instance_auf
= forms
.ChoiceField(
15 label
="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
16 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
18 membre_instance_auf_nom
= forms
.ChoiceField(
19 choices
= (('', '---------'),) + Chercheur
.INSTANCE_AUF_CHOICES
,
20 label
="Préciser laquelle", required
=False
22 membre_instance_auf_fonction
= forms
.CharField(label
="Préciser votre fonction", required
=False)
23 membre_instance_auf_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
24 expert_oif
= forms
.ChoiceField(label
="Avez-vous déjà été sollicité par l'OIF?", choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect())
25 expert_oif_details
= forms
.CharField(label
="Préciser à quel titre", required
=False,
26 help_text
="Fonction dans l'organisation, participation à une étude ou à une action, etc.")
27 expert_oif_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
28 membre_association_francophone
= forms
.ChoiceField(
29 label
="Êtes-vous membre d'une association ou d'une société savante francophone?",
30 help_text
="e.g. FIPF, Collège international de philosophie, AISLF, etc.",
31 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
33 membre_association_francophone_details
= forms
.CharField(label
="Préciser laquelle", required
=False)
34 membre_reseau_institutionnel
= forms
.ChoiceField(
35 label
="Êtes-vous (ou avez-vous déjà été) membre des instances d'un réseau institutionnel de l'AUF?",
36 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
38 membre_reseau_institutionnel_nom
= forms
.ChoiceField(
39 label
="Préciser le réseau institutionnel",
40 choices
=(('', '---------'),) + Chercheur
.RESEAU_INSTITUTIONNEL_CHOICES
,
43 membre_reseau_institutionnel_fonction
= forms
.CharField(required
=False, label
="Préciser votre fonction")
44 membre_reseau_institutionnel_dates
= forms
.CharField(required
=False, label
="Préciser les dates")
46 pays_etablissement
= forms
.ModelChoiceField(label
="Pays de l'établissement", queryset
=Pays
.objects
.all(), required
=True)
47 etablissement
= forms
.CharField(
48 label
="Nom de l'établissement", required
=True,
49 help_text
="Après avoir sélectionné un pays, une liste d'établissement apparaît dès la saisie partielle du nom de l'établissement."
52 expertises_auf
= forms
.ChoiceField(
53 label
="Êtes-vous disposé à réaliser des expertises pour l'AUF?",
54 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
57 theme_recherche
= forms
.CharField(
58 max_length
=1000, label
='Thèmes de recherche', help_text
='1000 signes maximum',
59 error_messages
=dict(max_length
="Veuillez entrer au maximum %(max)d signes (vous en avez entré %(length)d)."),
60 widget
=forms
.Textarea()
62 attestation
= forms
.BooleanField(
64 label
="J'atteste sur l'honneur l'exactitude des renseignements fournis sur le formulaire d'inscription et j'accepte leur publication en ligne."
66 discipline
= forms
.ModelChoiceField(
67 label
="Discipline", required
=True,
68 queryset
=Discipline
.objects
.all(),
69 help_text
="La liste des disciplines procède d'un choix fait par le conseil scientifique de l'AUF."
71 groupe_recherche
= forms
.CharField(
72 max_length
=255, label
='Groupe de recherche', required
=False,
73 help_text
="Indiquer l'appartenance à un groupe de recherche universitaire ou laboratoire ou groupement inter-universitaire"
75 url_site_web
= forms
.URLField(
76 label
='Adresse site Internet', required
=False,
77 help_text
="Si vous le souhaitez, vous pouvez y indiquer le lien qui renvoie vers une page personnelle (sur le site de votre établissement par exemple) plus complète."
82 fields
= ('nom', 'prenom', 'genre', 'adresse_postale', 'telephone',
84 'discipline', 'theme_recherche', 'groupe_recherche',
85 'mots_cles', 'url_site_web', 'url_blog',
86 'url_reseau_social', 'attestation', 'membre_instance_auf',
87 'membre_instance_auf_nom', 'membre_instance_auf_fonction',
88 'membre_instance_auf_dates', 'expert_oif',
89 'expert_oif_details', 'expert_oif_dates',
90 'membre_association_francophone',
91 'membre_association_francophone_details',
92 'membre_reseau_institutionnel',
93 'membre_reseau_institutionnel_nom',
94 'membre_reseau_institutionnel_fonction',
95 'membre_reseau_institutionnel_dates', 'expertises_auf')
97 def __init__(self
, data
=None, prefix
=None, instance
=None):
98 if instance
is not None:
100 if instance
.etablissement
:
101 initial
['etablissement'] = instance
.etablissement
.nom
102 initial
['pays_etablissement'] = instance
.etablissement
.pays_id
104 initial
['etablissement'] = instance
.etablissement_autre_nom
105 initial
['pays_etablissement'] = instance
.etablissement_autre_pays_id
108 super(ChercheurForm
, self
).__init__(data
=data
, prefix
=prefix
, instance
=instance
, initial
=initial
)
111 nom_etablissement
= self
.cleaned_data
['etablissement']
112 pays_etablissement
= self
.cleaned_data
['pays_etablissement']
113 etablissements
= Etablissement
.objects
.filter(nom
=nom_etablissement
, pays
=pays_etablissement
, actif
=True)
114 if etablissements
.count() > 0:
115 self
.instance
.etablissement
= etablissements
[0]
116 self
.instance
.etablissement_autre
= ''
117 self
.instance
.etablissement_autre_pays
= None
119 self
.instance
.etablissement
= None
120 self
.instance
.etablissement_autre_nom
= nom_etablissement
121 self
.instance
.etablissement_autre_pays
= pays_etablissement
122 super(ChercheurForm
, self
).save()
124 def clean_courriel(self
):
125 """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
126 avec le même courriel."""
127 courriel
= self
.cleaned_data
['courriel']
128 existing
= Chercheur
.objects
.filter(courriel
=courriel
, actif
=True)
129 if self
.instance
and self
.instance
.id:
130 existing
= existing
.exclude(id=self
.instance
.id)
132 raise forms
.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
135 def clean_membre_instance_auf(self
):
136 return bool(int(self
.cleaned_data
['membre_instance_auf']))
138 def clean_membre_instance_auf_nom(self
):
139 membre
= self
.cleaned_data
.get('membre_instance_auf')
140 nom
= self
.cleaned_data
.get('membre_instance_auf_nom')
141 if membre
and not nom
:
142 raise forms
.ValidationError('Veuillez préciser')
145 def clean_membre_instance_auf_fonction(self
):
146 membre
= self
.cleaned_data
.get('membre_instance_auf')
147 fonction
= self
.cleaned_data
.get('membre_instance_auf_fonction')
148 if membre
and not fonction
:
149 raise forms
.ValidationError('Veuillez préciser')
152 def clean_membre_instance_auf_dates(self
):
153 membre
= self
.cleaned_data
.get('membre_instance_auf')
154 dates
= self
.cleaned_data
.get('membre_instance_auf_dates')
155 if membre
and not dates
:
156 raise forms
.ValidationError('Veuillez préciser les dates')
159 def clean_expert_oif(self
):
160 return bool(int(self
.cleaned_data
['expert_oif']))
162 def clean_expert_oif_details(self
):
163 expert
= self
.cleaned_data
.get('expert_oif')
164 details
= self
.cleaned_data
.get('expert_oif_details')
165 if expert
and not details
:
166 raise forms
.ValidationError('Veuillez préciser')
169 def clean_expert_oif_dates(self
):
170 expert
= self
.cleaned_data
.get('expert_oif')
171 dates
= self
.cleaned_data
.get('expert_oif_dates')
172 if expert
and not dates
:
173 raise forms
.ValidationError('Veuillez préciser les dates')
176 def clean_membre_association_francophone(self
):
177 return bool(int(self
.cleaned_data
['membre_association_francophone']))
179 def clean_membre_association_francophone_details(self
):
180 membre
= self
.cleaned_data
.get('membre_association_francophone')
181 details
= self
.cleaned_data
.get('membre_association_francophone_details')
182 if membre
and not details
:
183 raise forms
.ValidationError('Veuillez préciser')
186 def clean_membre_reseau_institutionnel(self
):
187 return bool(int(self
.cleaned_data
['membre_reseau_institutionnel']))
189 def clean_membre_reseau_institutionnel_nom(self
):
190 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
191 nom
= self
.cleaned_data
.get('membre_reseau_institutionnel_nom')
192 if membre
and not nom
:
193 raise forms
.ValidationError('Veuillez préciser')
196 def clean_membre_reseau_institutionnel_fonction(self
):
197 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
198 fonction
= self
.cleaned_data
.get('membre_reseau_institutionnel_fonction')
199 if membre
and not fonction
:
200 raise forms
.ValidationError('Veuillez préciser')
203 def clean_membre_reseau_institutionnel_dates(self
):
204 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
205 dates
= self
.cleaned_data
.get('membre_reseau_institutionnel_dates')
206 if membre
and not dates
:
207 raise forms
.ValidationError('Veuillez préciser les dates')
210 def clean_expertises_auf(self
):
211 return bool(int(self
.cleaned_data
['expertises_auf']))
213 class ChercheurInscriptionForm(ChercheurForm
):
215 class Meta(ChercheurForm
.Meta
):
216 fields
= ChercheurForm
.Meta
.fields
+ ('courriel',)
218 class GroupesForm(forms
.Form
):
219 """Formulaire qui associe des groupes à un chercheur."""
220 groupes
= forms
.ModelMultipleChoiceField(
221 queryset
=Groupe
.objects
.all(),
222 label
='Domaines de recherche', required
=False,
223 help_text
="Ce champ est proposé à titre d'indication complémentaire, mais il n'est pas obligatoire. Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs."
226 def __init__(self
, data
=None, prefix
=None, chercheur
=None):
227 self
.chercheur
= chercheur
230 initial
['groupes'] = chercheur
.groupes
.values_list('id', flat
=True)
231 super(GroupesForm
, self
).__init__(data
=data
, prefix
=prefix
, initial
=initial
)
235 groupes
= self
.cleaned_data
['groupes']
236 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__in
=groupes
).delete()
238 ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=g
, actif
=1)
240 class PublicationForm(forms
.ModelForm
):
243 fields
= ('auteurs', 'titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
245 PublicationFormSet
= inlineformset_factory(Chercheur
, Publication
, form
=PublicationForm
, extra
=1)
247 class TheseForm(forms
.ModelForm
):
250 fields
= ('titre', 'annee', 'directeur', 'etablissement', 'nb_pages', 'url')
252 class ExpertiseForm(forms
.ModelForm
):
253 organisme_demandeur_visible
= forms
.ChoiceField(
254 label
="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
255 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect(), required
=False
259 fields
= ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
261 def clean_organisme_demandeur_visible(self
):
262 value
= self
.cleaned_data
['organisme_demandeur_visible']
263 return bool(int(value
)) if value
else False
265 ExpertiseFormSet
= inlineformset_factory(Chercheur
, Expertise
, form
=ExpertiseForm
, extra
=1)
267 class ChercheurFormGroup(object):
268 """Groupe de formulaires nécessaires pour l'inscription et l'édition
271 def __init__(self
, data
=None, chercheur
=None):
273 these
= chercheur
and chercheur
.these
274 except These
.DoesNotExist
:
276 chercheur_form_class
= ChercheurInscriptionForm
if chercheur
is None else ChercheurForm
277 self
.chercheur
= chercheur_form_class(data
=data
, prefix
='chercheur', instance
=chercheur
)
278 self
.groupes
= GroupesForm(data
=data
, prefix
='chercheur', chercheur
=chercheur
)
279 self
.expertises
= ExpertiseFormSet(data
=data
, prefix
='expertise', instance
=chercheur
)
280 self
.these
= TheseForm(data
=data
, prefix
='these', instance
=these
)
281 self
.publications
= PublicationFormSet(data
=data
, prefix
='publication', instance
=chercheur
)
284 def has_errors(self
):
285 return bool(self
.chercheur
.errors
or self
.groupes
.errors
or
286 self
.these
.errors
or self
.publications
.errors
or
287 self
.expertises
.errors
)
290 return self
.chercheur
.is_valid() and self
.groupes
.is_valid() and \
291 self
.these
.is_valid() and self
.publications
.is_valid() and \
292 self
.expertises
.is_valid()
297 # Enregistrer d'abord le chercheur lui-même.
298 self
.chercheur
.save()
300 # Puis les objets qui ont des clés étrangères vers nous
301 # puisqu'on a besoin d'un id.
302 chercheur
= self
.chercheur
.instance
303 self
.groupes
.chercheur
= chercheur
305 self
.these
.instance
.chercheur
= chercheur
307 self
.publications
.instance
= chercheur
308 self
.publications
.save()
309 self
.expertises
.instance
= chercheur
310 self
.expertises
.save()
311 return self
.chercheur
.instance
313 class RepertoireSearchForm (forms
.Form
):
314 q
= forms
.CharField(required
=False, label
="Rechercher dans tous les champs")
315 nom
= forms
.CharField(required
=False, label
="Nom")
316 domaine
= forms
.ModelChoiceField(queryset
=Groupe
.objects
.all(), required
=False, label
="Domaine de recherche", empty_label
="Tous")
317 groupe_recherche
= forms
.CharField(required
=False, label
="Groupe de recherche",
318 help_text
="ou Laboratoire, ou Groupement inter-universitaire")
319 statut
= forms
.ChoiceField(choices
=(('','Tous'),)+STATUT_CHOICES
+(('expert','Expert'),), required
=False, label
="Statut")
320 discipline
= forms
.ModelChoiceField(queryset
=Discipline
.objects
.all(), required
=False, label
="Discipline", empty_label
="Toutes")
321 pays
= forms
.ModelChoiceField(queryset
=Pays
.objects
.all(), required
=False, label
="Pays", empty_label
="Tous")
322 region
= forms
.ModelChoiceField(queryset
=Region
.objects
.all(), required
=False, label
="Région", empty_label
="Toutes",
323 help_text
="La région est ici définie au sens, non strictement géographique, du Bureau régional de l'AUF de référence.")
324 nord_sud
= forms
.ChoiceField(choices
=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required
=False, label
="Nord/Sud",
325 help_text
="Distinction d'ordre géopolitique et économique, non géographique, qui conditionne souvent l'attribution de soutiens par les agences internationales: on entend par Nord les pays développés, par Sud les pays en développement (pays les moins avancés, pays émergents et pays à économies en transition)")
326 activites_francophonie
= forms
.ChoiceField(required
=False, label
="Activités en Francophonie", choices
=(
328 ('instance_auf', "Membre d'une instance de l'AUF"),
329 ('expert_oif', "Sollicité par l'OIF"),
330 ('association_francophone', "Membre d'une association ou d'une société savante francophone"),
331 ('reseau_institutionnel', "Membre des instances d'un réseau institutionnel de l'AUF")
333 genre
= forms
.ChoiceField(choices
=((('', 'Tous'),) + GENRE_CHOICES
), required
=False, label
="Genre")
335 def __init__(self
, data
=None, region
=None):
336 super(RepertoireSearchForm
, self
).__init__(data
)
338 pays
= self
.fields
['pays']
339 pays
.queryset
= pays
.queryset
.filter(region
=region
)
341 def get_query_set(self
):
342 chercheurs
= Chercheur
.objects
344 q
= self
.cleaned_data
["q"]
346 chercheurs
= chercheurs
.search(q
)
347 nom
= self
.cleaned_data
['nom']
349 chercheurs
= chercheurs
.add_to_query('@(nom,prenom) ' + nom
)
350 groupe_recherche
= self
.cleaned_data
['groupe_recherche']
352 chercheurs
= chercheurs
.add_to_query('@groupe_recherche ' + groupe_recherche
)
353 discipline
= self
.cleaned_data
['discipline']
355 chercheurs
= chercheurs
.filter_discipline(discipline
)
356 region
= self
.cleaned_data
['region']
358 chercheurs
= chercheurs
.filter_region(region
)
359 statut
= self
.cleaned_data
["statut"]
361 if statut
== "expert":
362 chercheurs
= chercheurs
.filter_expert()
364 chercheurs
= chercheurs
.filter_statut(statut
)
365 domaine
= self
.cleaned_data
["domaine"]
367 chercheurs
= chercheurs
.filter_groupe(domaine
)
368 pays
= self
.cleaned_data
["pays"]
370 chercheurs
= chercheurs
.filter_pays(pays
)
371 nord_sud
= self
.cleaned_data
['nord_sud']
373 chercheurs
= chercheurs
.filter_nord_sud(nord_sud
)
374 genre
= self
.cleaned_data
['genre']
376 chercheurs
= chercheurs
.filter_genre(genre
)
377 activites_francophonie
= self
.cleaned_data
['activites_francophonie']
378 if activites_francophonie
== 'instance_auf':
379 chercheurs
= chercheurs
.filter(membre_instance_auf
=True)
380 elif activites_francophonie
== 'expert_oif':
381 chercheurs
= chercheurs
.filter(expert_oif
=True)
382 elif activites_francophonie
== 'association_francophone':
383 chercheurs
= chercheurs
.filter(membre_association_francophone
=True)
384 elif activites_francophonie
== 'reseau_institutionnel':
385 chercheurs
= chercheurs
.filter(membre_reseau_institutionnel
=True)
386 return chercheurs
.all()
388 class SendPasswordForm(forms
.Form
):
389 email
= forms
.EmailField(required
=True, label
="Adresse électronique")
390 def clean_email(self
):
391 cleaned_data
= self
.cleaned_data
392 email
= cleaned_data
.get("email")
395 Personne
.objects
.get(courriel
=email
)
397 raise forms
.ValidationError("Cette adresse n'existe pas dans notre base de données.")
400 class SetPasswordForm(forms
.Form
):
401 password
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Mot de passe")
402 password_repeat
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Confirmez votre mot de passe")
404 def clean_password_repeat(self
):
405 cleaned_data
= self
.cleaned_data
406 password
= cleaned_data
.get("password")
407 password_repeat
= cleaned_data
.get("password_repeat")
408 if password
and password_repeat
:
409 if password
!= password_repeat
:
410 raise forms
.ValidationError("Les mots de passe ne concordent pas")
411 return password_repeat