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(label
="Nom de l'établissement", required
=True)
49 expertises_auf
= forms
.ChoiceField(
50 label
="Êtes-vous disposé à réaliser des expertises pour l'AUF?",
51 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
54 theme_recherche
= forms
.CharField(
55 max_length
=1000, label
='Thèmes de recherche', help_text
='1000 signes maximum',
56 error_messages
=dict(max_length
="Veuillez entrer au maximum %(max)d signes (vous en avez entré %(length)d)."),
57 widget
=forms
.Textarea()
59 attestation
= forms
.BooleanField(
61 label
="J'atteste sur l'honneur l'exactitude des renseignements fournis sur le formulaire d'inscription et j'accepte leur publication en ligne."
66 fields
= ('nom', 'prenom', 'genre', 'statut', 'diplome',
67 'discipline', 'theme_recherche', 'groupe_recherche',
68 'mots_cles', 'url_site_web', 'url_blog',
69 'url_reseau_social', 'attestation', 'membre_instance_auf',
70 'membre_instance_auf_nom', 'membre_instance_auf_fonction',
71 'membre_instance_auf_dates', 'expert_oif',
72 'expert_oif_details', 'expert_oif_dates',
73 'membre_association_francophone',
74 'membre_association_francophone_details',
75 'membre_reseau_institutionnel',
76 'membre_reseau_institutionnel_nom',
77 'membre_reseau_institutionnel_fonction',
78 'membre_reseau_institutionnel_dates', 'expertises_auf')
80 def __init__(self
, data
=None, prefix
=None, instance
=None):
81 if instance
is not None:
83 if instance
.etablissement
:
84 initial
['etablissement'] = instance
.etablissement
.nom
85 initial
['pays_etablissement'] = instance
.etablissement
.pays_id
87 initial
['etablissement'] = instance
.etablissement_autre_nom
88 initial
['pays_etablissement'] = instance
.etablissement_autre_pays_id
91 super(ChercheurForm
, self
).__init__(data
=data
, prefix
=prefix
, instance
=instance
, initial
=initial
)
94 nom_etablissement
= self
.cleaned_data
['etablissement']
95 pays_etablissement
= self
.cleaned_data
['pays_etablissement']
96 etablissements
= Etablissement
.objects
.filter(nom
=nom_etablissement
, pays
=pays_etablissement
, actif
=True)
97 if etablissements
.count() > 0:
98 self
.instance
.etablissement
= etablissements
[0]
99 self
.instance
.etablissement_autre
= ''
100 self
.instance
.etablissement_autre_pays
= None
102 self
.instance
.etablissement
= None
103 self
.instance
.etablissement_autre_nom
= nom_etablissement
104 self
.instance
.etablissement_autre_pays
= pays_etablissement
105 super(ChercheurForm
, self
).save()
107 def clean_courriel(self
):
108 """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
109 avec le même courriel."""
110 courriel
= self
.cleaned_data
['courriel']
111 existing
= Chercheur
.objects
.filter(courriel
=courriel
, actif
=True)
112 if self
.instance
and self
.instance
.id:
113 existing
= existing
.exclude(id=self
.instance
.id)
115 raise forms
.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
118 def clean_membre_instance_auf(self
):
119 return bool(int(self
.cleaned_data
['membre_instance_auf']))
121 def clean_membre_instance_auf_nom(self
):
122 membre
= self
.cleaned_data
.get('membre_instance_auf')
123 nom
= self
.cleaned_data
.get('membre_instance_auf_nom')
124 if membre
and not nom
:
125 raise forms
.ValidationError('Veuillez préciser')
128 def clean_membre_instance_auf_fonction(self
):
129 membre
= self
.cleaned_data
.get('membre_instance_auf')
130 fonction
= self
.cleaned_data
.get('membre_instance_auf_fonction')
131 if membre
and not fonction
:
132 raise forms
.ValidationError('Veuillez préciser')
135 def clean_membre_instance_auf_dates(self
):
136 membre
= self
.cleaned_data
.get('membre_instance_auf')
137 dates
= self
.cleaned_data
.get('membre_instance_auf_dates')
138 if membre
and not dates
:
139 raise forms
.ValidationError('Veuillez préciser les dates')
142 def clean_expert_oif(self
):
143 return bool(int(self
.cleaned_data
['expert_oif']))
145 def clean_expert_oif_details(self
):
146 expert
= self
.cleaned_data
.get('expert_oif')
147 details
= self
.cleaned_data
.get('expert_oif_details')
148 if expert
and not details
:
149 raise forms
.ValidationError('Veuillez préciser')
152 def clean_expert_oif_dates(self
):
153 expert
= self
.cleaned_data
.get('expert_oif')
154 dates
= self
.cleaned_data
.get('expert_oif_dates')
155 if expert
and not dates
:
156 raise forms
.ValidationError('Veuillez préciser les dates')
159 def clean_membre_association_francophone(self
):
160 return bool(int(self
.cleaned_data
['membre_association_francophone']))
162 def clean_membre_association_francophone_details(self
):
163 membre
= self
.cleaned_data
.get('membre_association_francophone')
164 details
= self
.cleaned_data
.get('membre_association_francophone_details')
165 if membre
and not details
:
166 raise forms
.ValidationError('Veuillez préciser')
169 def clean_membre_reseau_institutionnel(self
):
170 return bool(int(self
.cleaned_data
['membre_reseau_institutionnel']))
172 def clean_membre_reseau_institutionnel_nom(self
):
173 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
174 nom
= self
.cleaned_data
.get('membre_reseau_institutionnel_nom')
175 if membre
and not nom
:
176 raise forms
.ValidationError('Veuillez préciser')
179 def clean_membre_reseau_institutionnel_fonction(self
):
180 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
181 fonction
= self
.cleaned_data
.get('membre_reseau_institutionnel_fonction')
182 if membre
and not fonction
:
183 raise forms
.ValidationError('Veuillez préciser')
186 def clean_membre_reseau_institutionnel_dates(self
):
187 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
188 dates
= self
.cleaned_data
.get('membre_reseau_institutionnel_dates')
189 if membre
and not dates
:
190 raise forms
.ValidationError('Veuillez préciser les dates')
193 def clean_expertises_auf(self
):
194 return bool(int(self
.cleaned_data
['expertises_auf']))
196 class ChercheurInscriptionForm(ChercheurForm
):
198 class Meta(ChercheurForm
.Meta
):
199 fields
= ChercheurForm
.Meta
.fields
+ ('courriel',)
201 class GroupesForm(forms
.Form
):
202 """Formulaire qui associe des groupes à un chercheur."""
203 groupes
= forms
.ModelMultipleChoiceField(
204 queryset
=Groupe
.objects
.all(),
205 label
='Domaines de recherche', required
=False,
206 help_text
="Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs."
209 def __init__(self
, data
=None, prefix
=None, chercheur
=None):
210 self
.chercheur
= chercheur
213 initial
['groupes'] = chercheur
.groupes
.values_list('id', flat
=True)
214 super(GroupesForm
, self
).__init__(data
=data
, prefix
=prefix
, initial
=initial
)
218 groupes
= self
.cleaned_data
['groupes']
219 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__in
=groupes
).delete()
221 ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=g
, actif
=1)
223 class PublicationForm(forms
.ModelForm
):
226 fields
= ('auteurs', 'titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
228 PublicationFormSet
= inlineformset_factory(Chercheur
, Publication
, form
=PublicationForm
, extra
=1)
230 class TheseForm(forms
.ModelForm
):
233 fields
= ('titre', 'annee', 'directeur', 'etablissement', 'nb_pages', 'url')
235 class ExpertiseForm(forms
.ModelForm
):
236 organisme_demandeur_visible
= forms
.ChoiceField(
237 label
="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
238 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect(), required
=False
242 fields
= ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
244 def clean_organisme_demandeur_visible(self
):
245 value
= self
.cleaned_data
['organisme_demandeur_visible']
246 return bool(int(value
)) if value
else False
248 ExpertiseFormSet
= inlineformset_factory(Chercheur
, Expertise
, form
=ExpertiseForm
, extra
=1)
250 class ChercheurFormGroup(object):
251 """Groupe de formulaires nécessaires pour l'inscription et l'édition
254 def __init__(self
, data
=None, chercheur
=None):
256 these
= chercheur
and chercheur
.these
257 except These
.DoesNotExist
:
259 chercheur_form_class
= ChercheurInscriptionForm
if chercheur
is None else ChercheurForm
260 self
.chercheur
= chercheur_form_class(data
=data
, prefix
='chercheur', instance
=chercheur
)
261 self
.groupes
= GroupesForm(data
=data
, prefix
='chercheur', chercheur
=chercheur
)
262 self
.expertises
= ExpertiseFormSet(data
=data
, prefix
='expertise', instance
=chercheur
)
263 self
.these
= TheseForm(data
=data
, prefix
='these', instance
=these
)
264 self
.publications
= PublicationFormSet(data
=data
, prefix
='publication', instance
=chercheur
)
267 def has_errors(self
):
268 return bool(self
.chercheur
.errors
or self
.groupes
.errors
or
269 self
.these
.errors
or self
.publications
.errors
or
270 self
.expertises
.errors
)
273 return self
.chercheur
.is_valid() and self
.groupes
.is_valid() and \
274 self
.these
.is_valid() and self
.publications
.is_valid() and \
275 self
.expertises
.is_valid()
280 # Enregistrer d'abord le chercheur lui-même.
281 self
.chercheur
.save()
283 # Puis les objets qui ont des clés étrangères vers nous
284 # puisqu'on a besoin d'un id.
285 chercheur
= self
.chercheur
.instance
286 self
.groupes
.chercheur
= chercheur
288 self
.these
.instance
.chercheur
= chercheur
290 self
.publications
.instance
= chercheur
291 self
.publications
.save()
292 self
.expertises
.instance
= chercheur
293 self
.expertises
.save()
294 return self
.chercheur
.instance
296 class RepertoireSearchForm (forms
.Form
):
297 q
= forms
.CharField(required
=False, label
="Rechercher dans tous les champs")
298 nom
= forms
.CharField(required
=False, label
="Nom")
299 domaine
= forms
.ModelChoiceField(queryset
=Groupe
.objects
.all(), required
=False, label
="Domaine de recherche", empty_label
="Tous")
300 groupe_recherche
= forms
.CharField(required
=False, label
="Groupe de recherche",
301 help_text
="ou Laboratoire, ou Groupement inter-universitaire")
302 statut
= forms
.ChoiceField(choices
=(('','Tous'),)+STATUT_CHOICES
+(('expert','Expert'),), required
=False, label
="Statut")
303 discipline
= forms
.ModelChoiceField(queryset
=Discipline
.objects
.all(), required
=False, label
="Discipline", empty_label
="Toutes")
304 pays
= forms
.ModelChoiceField(queryset
=Pays
.objects
.all(), required
=False, label
="Pays", empty_label
="Tous")
305 region
= forms
.ModelChoiceField(queryset
=Region
.objects
.all(), required
=False, label
="Région", empty_label
="Toutes",
306 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.")
307 nord_sud
= forms
.ChoiceField(choices
=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required
=False, label
="Nord/Sud",
308 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)")
309 activites_francophonie
= forms
.ChoiceField(required
=False, label
="Activités en Francophonie", choices
=(
311 ('instance_auf', "Membre d'une instance de l'AUF"),
312 ('expert_oif', "Sollicité par l'OIF"),
313 ('association_francophone', "Membre d'une association ou d'une société savante francophone"),
314 ('reseau_institutionnel', "Membre des instances d'un réseau institutionnel de l'AUF")
317 def __init__(self
, data
=None, region
=None):
318 super(RepertoireSearchForm
, self
).__init__(data
)
320 pays
= self
.fields
['pays']
321 pays
.queryset
= pays
.queryset
.filter(region
=region
)
323 def get_query_set(self
):
324 chercheurs
= Chercheur
.objects
326 q
= self
.cleaned_data
["q"]
328 chercheurs
= chercheurs
.search(q
)
329 nom
= self
.cleaned_data
['nom']
331 chercheurs
= chercheurs
.add_to_query('@(nom,prenom) ' + nom
)
332 groupe_recherche
= self
.cleaned_data
['groupe_recherche']
334 chercheurs
= chercheurs
.add_to_query('@groupe_recherche ' + groupe_recherche
)
335 discipline
= self
.cleaned_data
['discipline']
337 chercheurs
= chercheurs
.filter_discipline(discipline
)
338 region
= self
.cleaned_data
['region']
340 chercheurs
= chercheurs
.filter_region(region
)
341 statut
= self
.cleaned_data
["statut"]
343 if statut
== "expert":
344 chercheurs
= chercheurs
.filter_expert()
346 chercheurs
= chercheurs
.filter_statut(statut
)
347 domaine
= self
.cleaned_data
["domaine"]
349 chercheurs
= chercheurs
.filter_groupe(domaine
)
350 pays
= self
.cleaned_data
["pays"]
352 chercheurs
= chercheurs
.filter_pays(pays
)
353 nord_sud
= self
.cleaned_data
['nord_sud']
355 chercheurs
= chercheurs
.filter_nord_sud(nord_sud
)
356 activites_francophonie
= self
.cleaned_data
['activites_francophonie']
357 if activites_francophonie
== 'instance_auf':
358 chercheurs
= chercheurs
.filter(membre_instance_auf
=True)
359 elif activites_francophonie
== 'expert_oif':
360 chercheurs
= chercheurs
.filter(expert_oif
=True)
361 elif activites_francophonie
== 'association_francophone':
362 chercheurs
= chercheurs
.filter(membre_association_francophone
=True)
363 elif activites_francophonie
== 'reseau_institutionnel':
364 chercheurs
= chercheurs
.filter(membre_reseau_institutionnel
=True)
365 return chercheurs
.all()
367 class SendPasswordForm(forms
.Form
):
368 email
= forms
.EmailField(required
=True, label
="Adresse électronique")
369 def clean_email(self
):
370 cleaned_data
= self
.cleaned_data
371 email
= cleaned_data
.get("email")
374 Personne
.objects
.get(courriel
=email
)
376 raise forms
.ValidationError("Cette adresse n'existe pas dans notre base de données.")
379 class SetPasswordForm(forms
.Form
):
380 password
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Mot de passe")
381 password_repeat
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Confirmez votre mot de passe")
383 def clean_password_repeat(self
):
384 cleaned_data
= self
.cleaned_data
385 password
= cleaned_data
.get("password")
386 password_repeat
= cleaned_data
.get("password_repeat")
387 if password
and password_repeat
:
388 if password
!= password_repeat
:
389 raise forms
.ValidationError("Les mots de passe ne concordent pas")
390 return password_repeat