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', 'statut', 'diplome',
83 'discipline', 'theme_recherche', 'groupe_recherche',
84 'mots_cles', 'url_site_web', 'url_blog',
85 'url_reseau_social', 'attestation', 'membre_instance_auf',
86 'membre_instance_auf_nom', 'membre_instance_auf_fonction',
87 'membre_instance_auf_dates', 'expert_oif',
88 'expert_oif_details', 'expert_oif_dates',
89 'membre_association_francophone',
90 'membre_association_francophone_details',
91 'membre_reseau_institutionnel',
92 'membre_reseau_institutionnel_nom',
93 'membre_reseau_institutionnel_fonction',
94 'membre_reseau_institutionnel_dates', 'expertises_auf')
96 def __init__(self
, data
=None, prefix
=None, instance
=None):
97 if instance
is not None:
99 if instance
.etablissement
:
100 initial
['etablissement'] = instance
.etablissement
.nom
101 initial
['pays_etablissement'] = instance
.etablissement
.pays_id
103 initial
['etablissement'] = instance
.etablissement_autre_nom
104 initial
['pays_etablissement'] = instance
.etablissement_autre_pays_id
107 super(ChercheurForm
, self
).__init__(data
=data
, prefix
=prefix
, instance
=instance
, initial
=initial
)
110 nom_etablissement
= self
.cleaned_data
['etablissement']
111 pays_etablissement
= self
.cleaned_data
['pays_etablissement']
112 etablissements
= Etablissement
.objects
.filter(nom
=nom_etablissement
, pays
=pays_etablissement
, actif
=True)
113 if etablissements
.count() > 0:
114 self
.instance
.etablissement
= etablissements
[0]
115 self
.instance
.etablissement_autre
= ''
116 self
.instance
.etablissement_autre_pays
= None
118 self
.instance
.etablissement
= None
119 self
.instance
.etablissement_autre_nom
= nom_etablissement
120 self
.instance
.etablissement_autre_pays
= pays_etablissement
121 super(ChercheurForm
, self
).save()
123 def clean_courriel(self
):
124 """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
125 avec le même courriel."""
126 courriel
= self
.cleaned_data
['courriel']
127 existing
= Chercheur
.objects
.filter(courriel
=courriel
, actif
=True)
128 if self
.instance
and self
.instance
.id:
129 existing
= existing
.exclude(id=self
.instance
.id)
131 raise forms
.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
134 def clean_membre_instance_auf(self
):
135 return bool(int(self
.cleaned_data
['membre_instance_auf']))
137 def clean_membre_instance_auf_nom(self
):
138 membre
= self
.cleaned_data
.get('membre_instance_auf')
139 nom
= self
.cleaned_data
.get('membre_instance_auf_nom')
140 if membre
and not nom
:
141 raise forms
.ValidationError('Veuillez préciser')
144 def clean_membre_instance_auf_fonction(self
):
145 membre
= self
.cleaned_data
.get('membre_instance_auf')
146 fonction
= self
.cleaned_data
.get('membre_instance_auf_fonction')
147 if membre
and not fonction
:
148 raise forms
.ValidationError('Veuillez préciser')
151 def clean_membre_instance_auf_dates(self
):
152 membre
= self
.cleaned_data
.get('membre_instance_auf')
153 dates
= self
.cleaned_data
.get('membre_instance_auf_dates')
154 if membre
and not dates
:
155 raise forms
.ValidationError('Veuillez préciser les dates')
158 def clean_expert_oif(self
):
159 return bool(int(self
.cleaned_data
['expert_oif']))
161 def clean_expert_oif_details(self
):
162 expert
= self
.cleaned_data
.get('expert_oif')
163 details
= self
.cleaned_data
.get('expert_oif_details')
164 if expert
and not details
:
165 raise forms
.ValidationError('Veuillez préciser')
168 def clean_expert_oif_dates(self
):
169 expert
= self
.cleaned_data
.get('expert_oif')
170 dates
= self
.cleaned_data
.get('expert_oif_dates')
171 if expert
and not dates
:
172 raise forms
.ValidationError('Veuillez préciser les dates')
175 def clean_membre_association_francophone(self
):
176 return bool(int(self
.cleaned_data
['membre_association_francophone']))
178 def clean_membre_association_francophone_details(self
):
179 membre
= self
.cleaned_data
.get('membre_association_francophone')
180 details
= self
.cleaned_data
.get('membre_association_francophone_details')
181 if membre
and not details
:
182 raise forms
.ValidationError('Veuillez préciser')
185 def clean_membre_reseau_institutionnel(self
):
186 return bool(int(self
.cleaned_data
['membre_reseau_institutionnel']))
188 def clean_membre_reseau_institutionnel_nom(self
):
189 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
190 nom
= self
.cleaned_data
.get('membre_reseau_institutionnel_nom')
191 if membre
and not nom
:
192 raise forms
.ValidationError('Veuillez préciser')
195 def clean_membre_reseau_institutionnel_fonction(self
):
196 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
197 fonction
= self
.cleaned_data
.get('membre_reseau_institutionnel_fonction')
198 if membre
and not fonction
:
199 raise forms
.ValidationError('Veuillez préciser')
202 def clean_membre_reseau_institutionnel_dates(self
):
203 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
204 dates
= self
.cleaned_data
.get('membre_reseau_institutionnel_dates')
205 if membre
and not dates
:
206 raise forms
.ValidationError('Veuillez préciser les dates')
209 def clean_expertises_auf(self
):
210 return bool(int(self
.cleaned_data
['expertises_auf']))
212 class ChercheurInscriptionForm(ChercheurForm
):
214 class Meta(ChercheurForm
.Meta
):
215 fields
= ChercheurForm
.Meta
.fields
+ ('courriel',)
217 class GroupesForm(forms
.Form
):
218 """Formulaire qui associe des groupes à un chercheur."""
219 groupes
= forms
.ModelMultipleChoiceField(
220 queryset
=Groupe
.objects
.all(),
221 label
='Domaines de recherche', required
=False,
222 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."
225 def __init__(self
, data
=None, prefix
=None, chercheur
=None):
226 self
.chercheur
= chercheur
229 initial
['groupes'] = chercheur
.groupes
.values_list('id', flat
=True)
230 super(GroupesForm
, self
).__init__(data
=data
, prefix
=prefix
, initial
=initial
)
234 groupes
= self
.cleaned_data
['groupes']
235 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__in
=groupes
).delete()
237 ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=g
, actif
=1)
239 class PublicationForm(forms
.ModelForm
):
242 fields
= ('auteurs', 'titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
244 PublicationFormSet
= inlineformset_factory(Chercheur
, Publication
, form
=PublicationForm
, extra
=1)
246 class TheseForm(forms
.ModelForm
):
249 fields
= ('titre', 'annee', 'directeur', 'etablissement', 'nb_pages', 'url')
251 class ExpertiseForm(forms
.ModelForm
):
252 organisme_demandeur_visible
= forms
.ChoiceField(
253 label
="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
254 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect(), required
=False
258 fields
= ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
260 def clean_organisme_demandeur_visible(self
):
261 value
= self
.cleaned_data
['organisme_demandeur_visible']
262 return bool(int(value
)) if value
else False
264 ExpertiseFormSet
= inlineformset_factory(Chercheur
, Expertise
, form
=ExpertiseForm
, extra
=1)
266 class ChercheurFormGroup(object):
267 """Groupe de formulaires nécessaires pour l'inscription et l'édition
270 def __init__(self
, data
=None, chercheur
=None):
272 these
= chercheur
and chercheur
.these
273 except These
.DoesNotExist
:
275 chercheur_form_class
= ChercheurInscriptionForm
if chercheur
is None else ChercheurForm
276 self
.chercheur
= chercheur_form_class(data
=data
, prefix
='chercheur', instance
=chercheur
)
277 self
.groupes
= GroupesForm(data
=data
, prefix
='chercheur', chercheur
=chercheur
)
278 self
.expertises
= ExpertiseFormSet(data
=data
, prefix
='expertise', instance
=chercheur
)
279 self
.these
= TheseForm(data
=data
, prefix
='these', instance
=these
)
280 self
.publications
= PublicationFormSet(data
=data
, prefix
='publication', instance
=chercheur
)
283 def has_errors(self
):
284 return bool(self
.chercheur
.errors
or self
.groupes
.errors
or
285 self
.these
.errors
or self
.publications
.errors
or
286 self
.expertises
.errors
)
289 return self
.chercheur
.is_valid() and self
.groupes
.is_valid() and \
290 self
.these
.is_valid() and self
.publications
.is_valid() and \
291 self
.expertises
.is_valid()
296 # Enregistrer d'abord le chercheur lui-même.
297 self
.chercheur
.save()
299 # Puis les objets qui ont des clés étrangères vers nous
300 # puisqu'on a besoin d'un id.
301 chercheur
= self
.chercheur
.instance
302 self
.groupes
.chercheur
= chercheur
304 self
.these
.instance
.chercheur
= chercheur
306 self
.publications
.instance
= chercheur
307 self
.publications
.save()
308 self
.expertises
.instance
= chercheur
309 self
.expertises
.save()
310 return self
.chercheur
.instance
312 class RepertoireSearchForm (forms
.Form
):
313 q
= forms
.CharField(required
=False, label
="Rechercher dans tous les champs")
314 nom
= forms
.CharField(required
=False, label
="Nom")
315 domaine
= forms
.ModelChoiceField(queryset
=Groupe
.objects
.all(), required
=False, label
="Domaine de recherche", empty_label
="Tous")
316 groupe_recherche
= forms
.CharField(required
=False, label
="Groupe de recherche",
317 help_text
="ou Laboratoire, ou Groupement inter-universitaire")
318 statut
= forms
.ChoiceField(choices
=(('','Tous'),)+STATUT_CHOICES
+(('expert','Expert'),), required
=False, label
="Statut")
319 discipline
= forms
.ModelChoiceField(queryset
=Discipline
.objects
.all(), required
=False, label
="Discipline", empty_label
="Toutes")
320 pays
= forms
.ModelChoiceField(queryset
=Pays
.objects
.all(), required
=False, label
="Pays", empty_label
="Tous")
321 region
= forms
.ModelChoiceField(queryset
=Region
.objects
.all(), required
=False, label
="Région", empty_label
="Toutes",
322 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.")
323 nord_sud
= forms
.ChoiceField(choices
=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required
=False, label
="Nord/Sud",
324 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)")
325 activites_francophonie
= forms
.ChoiceField(required
=False, label
="Activités en Francophonie", choices
=(
327 ('instance_auf', "Membre d'une instance de l'AUF"),
328 ('expert_oif', "Sollicité par l'OIF"),
329 ('association_francophone', "Membre d'une association ou d'une société savante francophone"),
330 ('reseau_institutionnel', "Membre des instances d'un réseau institutionnel de l'AUF")
332 genre
= forms
.ChoiceField(choices
=((('', 'Tous'),) + GENRE_CHOICES
), required
=False, label
="Genre", help_text
="Homme, Femme ou les deux")
334 def __init__(self
, data
=None, region
=None):
335 super(RepertoireSearchForm
, self
).__init__(data
)
337 pays
= self
.fields
['pays']
338 pays
.queryset
= pays
.queryset
.filter(region
=region
)
340 def get_query_set(self
):
341 chercheurs
= Chercheur
.objects
343 q
= self
.cleaned_data
["q"]
345 chercheurs
= chercheurs
.search(q
)
346 nom
= self
.cleaned_data
['nom']
348 chercheurs
= chercheurs
.add_to_query('@(nom,prenom) ' + nom
)
349 groupe_recherche
= self
.cleaned_data
['groupe_recherche']
351 chercheurs
= chercheurs
.add_to_query('@groupe_recherche ' + groupe_recherche
)
352 discipline
= self
.cleaned_data
['discipline']
354 chercheurs
= chercheurs
.filter_discipline(discipline
)
355 region
= self
.cleaned_data
['region']
357 chercheurs
= chercheurs
.filter_region(region
)
358 statut
= self
.cleaned_data
["statut"]
360 if statut
== "expert":
361 chercheurs
= chercheurs
.filter_expert()
363 chercheurs
= chercheurs
.filter_statut(statut
)
364 domaine
= self
.cleaned_data
["domaine"]
366 chercheurs
= chercheurs
.filter_groupe(domaine
)
367 pays
= self
.cleaned_data
["pays"]
369 chercheurs
= chercheurs
.filter_pays(pays
)
370 nord_sud
= self
.cleaned_data
['nord_sud']
372 chercheurs
= chercheurs
.filter_nord_sud(nord_sud
)
373 genre
= self
.cleaned_data
['genre']
375 chercheurs
= chercheurs
.filter_genre(genre
)
376 activites_francophonie
= self
.cleaned_data
['activites_francophonie']
377 if activites_francophonie
== 'instance_auf':
378 chercheurs
= chercheurs
.filter(membre_instance_auf
=True)
379 elif activites_francophonie
== 'expert_oif':
380 chercheurs
= chercheurs
.filter(expert_oif
=True)
381 elif activites_francophonie
== 'association_francophone':
382 chercheurs
= chercheurs
.filter(membre_association_francophone
=True)
383 elif activites_francophonie
== 'reseau_institutionnel':
384 chercheurs
= chercheurs
.filter(membre_reseau_institutionnel
=True)
385 return chercheurs
.all()
387 class SendPasswordForm(forms
.Form
):
388 email
= forms
.EmailField(required
=True, label
="Adresse électronique")
389 def clean_email(self
):
390 cleaned_data
= self
.cleaned_data
391 email
= cleaned_data
.get("email")
394 Personne
.objects
.get(courriel
=email
)
396 raise forms
.ValidationError("Cette adresse n'existe pas dans notre base de données.")
399 class SetPasswordForm(forms
.Form
):
400 password
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Mot de passe")
401 password_repeat
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Confirmez votre mot de passe")
403 def clean_password_repeat(self
):
404 cleaned_data
= self
.cleaned_data
405 password
= cleaned_data
.get("password")
406 password_repeat
= cleaned_data
.get("password_repeat")
407 if password
and password_repeat
:
408 if password
!= password_repeat
:
409 raise forms
.ValidationError("Les mots de passe ne concordent pas")
410 return password_repeat