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 PersonneForm(forms
.ModelForm
):
12 genre
= forms
.ChoiceField(widget
=forms
.RadioSelect(), choices
=GENRE_CHOICES
)
16 fields
= ('nom', 'prenom', 'courriel', 'genre')
18 class PersonneInscriptionForm(PersonneForm
):
19 password
= forms
.CharField(widget
=forms
.PasswordInput(), label
="Mot de passe")
21 class Meta(PersonneForm
.Meta
):
22 fields
= ('nom', 'prenom', 'courriel', 'password', 'genre')
24 def clean_password(self
):
25 """Encrypter le mot de passe avant de le mettre dans la BD."""
26 return hashlib
.md5(self
.cleaned_data
['password']).hexdigest()
28 class ChercheurForm(forms
.ModelForm
):
29 """Formulaire d'édition d'un chercheur."""
30 ETABLISSEMENT_CHOICES
= ((id, nom
if len(nom
) < 80 else nom
[:80] + '...')
31 for id, nom
in Etablissement
.objects
.filter(membre
=True).values_list('id', 'nom'))
33 membre_instance_auf
= forms
.ChoiceField(
34 label
="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
35 help_text
="e.g. conseil scientifique, conseil associatif, commission régionale d'experts",
36 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
38 membre_instance_auf_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
39 expert_oif
= forms
.ChoiceField(label
="Êtes-vous expert de l'OIF?", choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect())
40 membre_association_francophone
= forms
.ChoiceField(
41 label
="Êtes-vous membre d'une association ou d'une société savante francophone?",
42 help_text
="e.g. FIPF, Collège international de philosophie, AISLF, etc.",
43 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
45 membre_association_francophone_details
= forms
.CharField(label
="Préciser laquelle", required
=False)
46 membre_reseau_institutionnel
= forms
.ChoiceField(
47 label
="Avez-vous fait partie des instances d'un réseau institutionnel de l'AUF?",
48 help_text
="e.g. AFELSH, RIFFEF, CIDMEF, etc.",
49 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
51 membre_reseau_institutionnel_details
= forms
.CharField(required
=False, label
="Préciser lesquelles et votre fonction")
52 membre_reseau_institutionnel_dates
= forms
.CharField(required
=False, label
="Préciser les dates")
54 etablissement
= forms
.ChoiceField(label
='Etablissement', required
=False, choices
=chain([('', '---------')], ETABLISSEMENT_CHOICES
))
58 fields
= ('statut', 'diplome', 'etablissement',
59 'etablissement_autre_nom', 'etablissement_autre_pays',
60 'discipline', 'theme_recherche', 'groupe_recherche', 'mots_cles',
61 'url_site_web', 'url_blog', 'url_reseau_social',
62 'membre_instance_auf', 'membre_instance_auf_dates',
63 'expert_oif', 'membre_association_francophone', 'membre_association_francophone_details',
64 'membre_reseau_institutionnel', 'membre_reseau_institutionnel_details',
65 'membre_reseau_institutionnel_dates')
67 def clean_membre_instance_auf(self
):
68 return bool(int(self
.cleaned_data
['membre_instance_auf']))
70 def clean_membre_instance_auf_dates(self
):
71 membre
= self
.cleaned_data
.get('membre_instance_auf')
72 dates
= self
.cleaned_data
.get('membre_instance_auf_dates')
73 if membre
and not dates
:
74 raise forms
.ValidationError('Veuillez préciser les dates')
77 def clean_expert_oif(self
):
78 return bool(int(self
.cleaned_data
['expert_oif']))
80 def clean_membre_association_francophone(self
):
81 return bool(int(self
.cleaned_data
['membre_association_francophone']))
83 def clean_membre_association_francophone_details(self
):
84 membre
= self
.cleaned_data
.get('membre_association_francophone')
85 details
= self
.cleaned_data
.get('membre_association_francophone_details')
86 if membre
and not details
:
87 raise forms
.ValidationError('Veuillez préciser')
90 def clean_membre_reseau_institutionnel(self
):
91 return bool(int(self
.cleaned_data
['membre_reseau_institutionnel']))
93 def clean_membre_reseau_institutionnel_details(self
):
94 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
95 details
= self
.cleaned_data
.get('membre_reseau_institutionnel_details')
96 if membre
and not details
:
97 raise forms
.ValidationError('Veuillez préciser')
100 def clean_membre_reseau_institutionnel_dates(self
):
101 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
102 dates
= self
.cleaned_data
.get('membre_reseau_institutionnel_dates')
103 if membre
and not dates
:
104 raise forms
.ValidationError('Veuillez préciser les dates')
107 def clean_etablissement(self
):
108 etablissement
= self
.cleaned_data
['etablissement']
110 return Etablissement
.objects
.get(id=etablissement
)
113 etablissement
= self
.cleaned_data
['etablissement']
114 etablissement_autre_nom
= self
.cleaned_data
['etablissement_autre_nom']
115 etablissement_autre_pays
= self
.cleaned_data
['etablissement_autre_pays']
116 if not etablissement
:
117 if not etablissement_autre_nom
:
118 self
._errors
['etablissement'] = self
.error_class([u
"Vous devez renseigner l'établissement"])
119 elif not etablissement_autre_pays
:
120 self
._errors
['etablissement_autre_pays'] = self
.error_class([u
"Vous devez renseigner le pays de l'établissement"])
121 return self
.cleaned_data
123 class GroupesForm(forms
.Form
):
124 """Formulaire qui associe des groupes à un chercheur."""
125 groupes
= forms
.ModelMultipleChoiceField(
126 queryset
=Groupe
.objects
.all(),
127 label
='Domaines de recherche', required
=False,
128 help_text
="Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs."
131 def __init__(self
, data
=None, prefix
=None, chercheur
=None):
132 self
.chercheur
= chercheur
135 initial
['groupes'] = chercheur
.groupes
.values_list('id', flat
=True)
136 super(GroupesForm
, self
).__init__(data
=data
, prefix
=prefix
, initial
=initial
)
140 groupes
= self
.cleaned_data
['groupes']
141 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__in
=groupes
).delete()
143 ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=g
, actif
=1)
145 class PublicationForm(forms
.ModelForm
):
148 fields
= ('titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
150 class TheseForm(PublicationForm
):
151 titre
= forms
.CharField(required
=True, label
="Titre de la thèse ou du mémoire")
152 annee
= forms
.IntegerField(required
=True, label
="Année de soutenance (réalisée ou prévue)")
153 editeur
= forms
.CharField(required
=True, label
="Directeur de thèse ou de mémoire")
154 lieu_edition
= forms
.CharField(required
=True, label
="Établissement de soutenance")
157 fields
= ('titre', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
159 class ExpertiseForm(forms
.ModelForm
):
160 organisme_demandeur_visible
= forms
.ChoiceField(
161 label
="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
162 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect(), required
=False
166 fields
= ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
168 def clean_organisme_demandeur_visible(self
):
169 value
= self
.cleaned_data
['organisme_demandeur_visible']
170 return bool(int(value
)) if value
else False
172 ExpertiseFormSet
= inlineformset_factory(Chercheur
, Expertise
, form
=ExpertiseForm
, extra
=1)
174 class ChercheurFormGroup(object):
175 """Groupe de formulaires nécessaires pour l'inscription et l'édition
178 def __init__(self
, data
=None, chercheur
=None):
179 personne_form_class
= PersonneInscriptionForm
if chercheur
is None else PersonneForm
180 self
.chercheur
= ChercheurForm(data
=data
, prefix
='chercheur', instance
=chercheur
)
181 self
.groupes
= GroupesForm(data
=data
, prefix
='chercheur', chercheur
=chercheur
)
182 self
.personne
= personne_form_class(data
=data
, prefix
='personne', instance
=chercheur
and chercheur
.personne
)
183 self
.publication1
= PublicationForm(data
=data
, prefix
='publication1', instance
=chercheur
and chercheur
.publication1
)
184 self
.publication2
= PublicationForm(data
=data
, prefix
='publication2', instance
=chercheur
and chercheur
.publication2
)
185 self
.publication3
= PublicationForm(data
=data
, prefix
='publication3', instance
=chercheur
and chercheur
.publication3
)
186 self
.publication4
= PublicationForm(data
=data
, prefix
='publication4', instance
=chercheur
and chercheur
.publication4
)
187 self
.these
= TheseForm(data
=data
, prefix
='these', instance
=chercheur
and chercheur
.these
)
188 self
.expertises
= ExpertiseFormSet(data
=data
, prefix
='expertise', instance
=chercheur
)
191 def has_errors(self
):
192 return bool(self
.chercheur
.errors
or self
.personne
.errors
or self
.groupes
.errors
or
193 self
.publication1
.errors
or self
.publication2
.errors
or self
.publication3
.errors
or
194 self
.publication4
.errors
or self
.these
.errors
or self
.expertises
.errors
)
197 return self
.chercheur
.is_valid() and self
.personne
.is_valid() and self
.groupes
.is_valid() and \
198 self
.publication1
.is_valid() and self
.publication2
.is_valid() and \
199 self
.publication3
.is_valid() and self
.publication4
.is_valid() and \
200 self
.these
.is_valid() and self
.expertises
.is_valid()
205 chercheur
= self
.chercheur
.instance
207 # Enregistrer d'abord les clés étrangères car on doit les stocker dans
209 chercheur
.personne
= self
.personne
.save()
210 if self
.publication1
.cleaned_data
['titre']:
211 chercheur
.publication1
= self
.publication1
.save()
212 if self
.publication2
.cleaned_data
['titre']:
213 chercheur
.publication2
= self
.publication2
.save()
214 if self
.publication3
.cleaned_data
['titre']:
215 chercheur
.publication3
= self
.publication3
.save()
216 if self
.publication4
.cleaned_data
['titre']:
217 chercheur
.publication4
= self
.publication4
.save()
218 chercheur
.these
= self
.these
.save()
220 # Puis enregistrer le chercheur lui-même.
221 self
.chercheur
.save()
223 # Puis les many-to-many puisqu'on a besoin d'un id.
224 self
.groupes
.chercheur
= chercheur
226 self
.expertises
.instance
= chercheur
227 self
.expertises
.save()
229 class RepertoireSearchForm (forms
.Form
):
230 q
= forms
.CharField(required
=False, label
="Rechercher dans tous les champs")
231 nom
= forms
.CharField(required
=False, label
="Nom")
232 domaine
= forms
.ModelChoiceField(queryset
=Groupe
.objects
.all(), required
=False, label
="Domaine de recherche", empty_label
="Tous")
233 groupe_recherche
= forms
.CharField(required
=False, label
="Groupe de recherche",
234 help_text
="ou Laboratoire, ou Groupement inter-universitaire")
235 statut
= forms
.ChoiceField(choices
=(('','Tous'),)+STATUT_CHOICES
+(('expert','Expert'),), required
=False, label
="Statut")
236 discipline
= forms
.ModelChoiceField(queryset
=Discipline
.objects
.all(), required
=False, label
="Discipline", empty_label
="Toutes")
237 pays
= forms
.ModelChoiceField(queryset
=Pays
.objects
.all(), required
=False, label
="Pays", empty_label
="Tous")
238 region
= forms
.ModelChoiceField(queryset
=Region
.objects
.all(), required
=False, label
="Région", empty_label
="Toutes",
239 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.")
240 nord_sud
= forms
.ChoiceField(choices
=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required
=False, label
="Nord/Sud",
241 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 les plus développés, par Sud les pays en voie de développement.")
243 def __init__(self
, data
=None, region
=None):
244 super(RepertoireSearchForm
, self
).__init__(data
)
246 pays
= self
.fields
['pays']
247 pays
.queryset
= pays
.queryset
.filter(region
=region
)
249 def get_query_set(self
):
250 qs
= Chercheur
.objects
.all()
252 nom
= self
.cleaned_data
['nom']
254 qs
= qs
.search_nom(nom
)
255 domaine
= self
.cleaned_data
["domaine"]
257 qs
= qs
.filter(groupes
=domaine
)
258 groupe_recherche
= self
.cleaned_data
['groupe_recherche']
260 for word
in groupe_recherche
.split():
261 qs
= qs
.filter(groupe_recherche__icontains
=word
)
262 q
= self
.cleaned_data
["q"]
265 statut
= self
.cleaned_data
["statut"]
267 if statut
== "expert":
268 qs
= qs
.exclude(expertises
=None)
270 qs
= qs
.filter(statut
=statut
)
271 discipline
= self
.cleaned_data
['discipline']
273 qs
= qs
.filter_discipline(discipline
)
274 region
= self
.cleaned_data
['region']
276 qs
= qs
.filter_region(region
)
277 pays
= self
.cleaned_data
["pays"]
279 qs
= qs
.filter(Q(etablissement__pays
=pays
) |
Q(etablissement_autre_pays
=pays
))
280 nord_sud
= self
.cleaned_data
['nord_sud']
282 qs
= qs
.filter(Q(etablissement__pays__nord_sud
=nord_sud
) |
Q(etablissement_autre_pays__nord_sud
=nord_sud
))
285 class SendPasswordForm(forms
.Form
):
286 email
= forms
.EmailField(required
=True, label
="Adresse électronique")
287 def clean_email(self
):
288 cleaned_data
= self
.cleaned_data
289 email
= cleaned_data
.get("email")
292 Utilisateur
.objects
.get(courriel
=email
)
294 raise forms
.ValidationError("Cette adresse n'existe pas dans notre base de données.")
297 class NewPasswordForm(forms
.Form
):
298 password
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Mot de passe")
299 password_repeat
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Confirmez mot de passe")
300 def clean_password_repeat(self
):
301 cleaned_data
= self
.cleaned_data
302 password
= cleaned_data
.get("password")
303 password_repeat
= cleaned_data
.get("password_repeat")
304 if password
and password_repeat
:
305 if password
!= password_repeat
:
306 raise forms
.ValidationError("Les mots de passe ne concordent pas")
307 return password_repeat