Utilisé l'héritage de modèles entre Chercheur et Personne
authorEric Mc Sween <eric.mcsween@gmail.com>
Tue, 7 Dec 2010 22:29:03 +0000 (17:29 -0500)
committerEric Mc Sween <eric.mcsween@gmail.com>
Tue, 7 Dec 2010 22:29:03 +0000 (17:29 -0500)
Demande #851

auf_savoirs_en_partage/authentification.py
auf_savoirs_en_partage/chercheurs/admin.py
auf_savoirs_en_partage/chercheurs/forms.py
auf_savoirs_en_partage/chercheurs/models.py
auf_savoirs_en_partage/chercheurs/views.py
auf_savoirs_en_partage/context_processors.py
auf_savoirs_en_partage/sql/2010-12-07.sql [new file with mode: 0644]
auf_savoirs_en_partage/templates/chercheurs/chercheur_form.html
auf_savoirs_en_partage/templates/chercheurs/edit.html
auf_savoirs_en_partage/templates/chercheurs/fiche.html

index 8215567..3dd916e 100644 (file)
@@ -5,7 +5,7 @@ import settings
 from django.contrib.auth.backends import ModelBackend
 from django.contrib.auth.models import User as DjangoUser, check_password
 
-from chercheurs.models import Utilisateur as RemoteUser
+from chercheurs.models import Personne as RemoteUser
 
 class CascadeBackend(ModelBackend):
     def authenticate(self, username=None, password=None):
@@ -15,7 +15,7 @@ class CascadeBackend(ModelBackend):
         # Cherche les comptes roa+locaux
         remoteUser = localUser = None
         try:
-            remoteUser = RemoteUser.objects.get(courriel=email, actif=True)
+            remoteUser = RemoteUser.objects.get(courriel=email)
             if settings.AUTH_PASSWORD_REQUIRED and not remoteUser.check_password(password):
                 remoteUser = None
         except:
index 158aac2..dcb00e8 100644 (file)
@@ -10,7 +10,7 @@ class ChercheurAdmin(admin.ModelAdmin):
     list_filter = ('groupes',)
     list_per_page = 25
     actions = ('remove_from_group',)
-    search_fields = ('personne__nom', 'personne__prenom')
+    search_fields = ('nom', 'prenom')
 
     def remove_from_group(self, request, queryset):
         groupe_id = request.GET.get('groupes__id__exact')
index 5c8ba03..eb01410 100644 (file)
@@ -8,45 +8,9 @@ from models import *
 
 OUI_NON_CHOICES = (('1', 'Oui'), ('0', 'Non'))
 
-class PersonneForm(forms.ModelForm):
-    genre = forms.ChoiceField(widget=forms.RadioSelect(), choices=GENRE_CHOICES)
-
-    class Meta:
-        model = Utilisateur
-        fields = ('nom', 'prenom', 'courriel', 'genre')
-        
-    def clean_courriel(self):
-        """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
-           avec le même courriel."""
-        courriel = self.cleaned_data['courriel']
-        existing = Personne.objects.filter(courriel=courriel, actif=True)
-        if self.instance and self.instance.id:
-            existing = existing.exclude(id=self.instance.id)
-        if existing.count():
-            raise forms.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
-        return courriel
-        
-class PersonneInscriptionForm(PersonneForm):
-    password = forms.CharField(widget=forms.PasswordInput(), label="Mot de passe") 
-    password_confirmation = forms.CharField(widget=forms.PasswordInput(), label="Confirmez votre mot de passe")
-
-    class Meta(PersonneForm.Meta):
-        fields = ('nom', 'prenom', 'courriel', 'password', 'password_confirmation', 'genre')
-        
-    def clean_password_confirmation(self):
-        """S'assurer que le mot de passe et la confirmation sont identiques."""
-        password = self.cleaned_data.get('password')
-        confirmation = self.cleaned_data.get('password_confirmation')
-        if password != confirmation:
-            raise forms.ValidationError('Les deux mots de passe ne correspondent pas.')
-        return confirmation
-
-    def save(self):
-        self.instance.set_password(self.cleaned_data['password'])
-        return super(PersonneInscriptionForm, self).save()
-
 class ChercheurForm(forms.ModelForm):
     """Formulaire d'édition d'un chercheur."""
+    genre = forms.ChoiceField(widget=forms.RadioSelect(), choices=GENRE_CHOICES)
     membre_instance_auf = forms.ChoiceField(
         label="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
         help_text="e.g. conseil scientifique, conseil associatif, commission régionale d'experts",
@@ -92,7 +56,8 @@ class ChercheurForm(forms.ModelForm):
 
     class Meta:
         model = Chercheur
-        fields = ('statut', 'diplome', 'discipline', 'theme_recherche',
+        fields = ('nom', 'prenom', 'courriel', 'genre',
+                  'statut', 'diplome', 'discipline', 'theme_recherche',
                   'groupe_recherche', 'mots_cles', 'url_site_web',
                   'url_blog', 'url_reseau_social', 'attestation',
                   'membre_instance_auf', 'membre_instance_auf_details',
@@ -131,6 +96,17 @@ class ChercheurForm(forms.ModelForm):
             self.instance.etablissement_autre_pays = pays_etablissement
         super(ChercheurForm, self).save()
 
+    def clean_courriel(self):
+        """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
+           avec le même courriel."""
+        courriel = self.cleaned_data['courriel']
+        existing = Chercheur.objects.filter(courriel=courriel, actif=True)
+        if self.instance and self.instance.id:
+            existing = existing.exclude(id=self.instance.id)
+        if existing.count():
+            raise forms.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
+        return courriel
+        
     def clean_membre_instance_auf(self):
         return bool(int(self.cleaned_data['membre_instance_auf']))
     
@@ -195,6 +171,25 @@ class ChercheurForm(forms.ModelForm):
     def clean_expertises_auf(self):
         return bool(int(self.cleaned_data['expertises_auf']))
 
+class ChercheurInscriptionForm(ChercheurForm):
+    password = forms.CharField(widget=forms.PasswordInput(), label="Mot de passe") 
+    password_confirmation = forms.CharField(widget=forms.PasswordInput(), label="Confirmez votre mot de passe")
+
+    class Meta(ChercheurForm.Meta):
+        fields = ChercheurForm.Meta.fields + ('password',)
+        
+    def clean_password_confirmation(self):
+        """S'assurer que le mot de passe et la confirmation sont identiques."""
+        password = self.cleaned_data.get('password')
+        confirmation = self.cleaned_data.get('password_confirmation')
+        if password != confirmation:
+            raise forms.ValidationError('Les deux mots de passe ne correspondent pas.')
+        return confirmation
+
+    def save(self):
+        self.instance.set_password(self.cleaned_data['password'])
+        return super(ChercheurInscriptionForm, self).save()
+
 class GroupesForm(forms.Form):
     """Formulaire qui associe des groupes à un chercheur."""
     groupes = forms.ModelMultipleChoiceField(
@@ -249,37 +244,33 @@ class ChercheurFormGroup(object):
        d'un chercheur."""
 
     def __init__(self, data=None, chercheur=None):
-        personne_form_class = PersonneInscriptionForm if chercheur is None else PersonneForm
-        self.chercheur = ChercheurForm(data=data, prefix='chercheur', instance=chercheur)
+        chercheur_form_class = ChercheurInscriptionForm if chercheur is None else ChercheurForm
+        self.chercheur = chercheur_form_class(data=data, prefix='chercheur', instance=chercheur)
         self.groupes = GroupesForm(data=data, prefix='chercheur', chercheur=chercheur)
-        self.personne = personne_form_class(data=data, prefix='personne', instance=chercheur and chercheur.personne.utilisateur)
         self.expertises = ExpertiseFormSet(data=data, prefix='expertise', instance=chercheur)
         self.these = TheseForm(data=data, prefix='these', instance=chercheur and chercheur.these)
         self.publications = PublicationFormSet(data=data, prefix='publication', instance=chercheur)
 
     @property
     def has_errors(self):
-        return bool(self.chercheur.errors or self.personne.errors or self.groupes.errors or
-                    self.these.errors or self.publications.errors or self.expertises.errors)
+        return bool(self.chercheur.errors or self.groupes.errors or
+                    self.these.errors or self.publications.errors or
+                    self.expertises.errors)
 
     def is_valid(self):
-        return self.chercheur.is_valid() and self.personne.is_valid() and self.groupes.is_valid() and \
-               self.these.is_valid() and self.publications.is_valid() and self.expertises.is_valid()
+        return self.chercheur.is_valid() and self.groupes.is_valid() and \
+               self.these.is_valid() and self.publications.is_valid() and \
+               self.expertises.is_valid()
 
     def save(self):
         if self.is_valid():
 
-            chercheur = self.chercheur.instance
-
-            # Enregistrer d'abord les clés étrangères car on doit les stocker dans
-            # l'objet chercheur.
-            chercheur.personne = self.personne.save()
-
-            # Puis enregistrer le chercheur lui-même.
+            # Enregistrer d'abord le chercheur lui-même.
             self.chercheur.save()
 
             # Puis les objets qui ont des clés étrangères vers nous
             # puisqu'on a besoin d'un id.
+            chercheur = self.chercheur.instance
             self.groupes.chercheur = chercheur
             self.groupes.save()
             self.these.instance.chercheur = chercheur
@@ -351,7 +342,7 @@ class SendPasswordForm(forms.Form):
         email = cleaned_data.get("email")
         if email:
             try:
-                Utilisateur.objects.get(courriel=email, actif=True)
+                Personne.objects.get(courriel=email)
             except:
                 raise forms.ValidationError("Cette adresse n'existe pas dans notre base de données.")       
         return email
index 10eb4b3..b65b59f 100644 (file)
@@ -9,8 +9,6 @@ from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySe
 
 GENRE_CHOICES = (('m', 'Homme'), ('f', 'Femme'))
 class Personne(models.Model):
-
-    id = models.AutoField(primary_key=True)
     salutation = models.CharField(max_length=128, null=True, blank=True)
     nom = models.CharField(max_length=255)
     prenom = models.CharField(max_length=128, verbose_name='prénom')
@@ -22,15 +20,13 @@ class Personne(models.Model):
     genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     commentaire = models.TextField(verbose_name='commentaires', null=True, blank=True)
     actif = models.BooleanField(editable=False, default=True)
+    encrypted_password = models.CharField(db_column='password', max_length=35, verbose_name='Mot de passe')
 
     def __unicode__(self):
         return u"%s %s, %s" % (self.prenom, self.nom, self.courriel)
 
     class Meta:
-        ordering = ["prenom", "nom"]
-
-class Utilisateur(Personne):
-    encrypted_password = models.CharField(db_column='password', max_length=35, verbose_name = 'Mot de passe')
+        ordering = ["nom", "prenom"]
 
     def set_password(self, clear_password):
         self.encrypted_password = self.encrypt_password(clear_password)
@@ -115,12 +111,9 @@ class ChercheurManager(SEPManager):
         return self.get_query_set().filter_expert()
 
 STATUT_CHOICES = (('enseignant', 'Enseignant-chercheur dans un établissement'), ('etudiant', 'Étudiant-chercheur doctorant'), ('independant', 'Chercheur indépendant docteur'))
-class Chercheur(models.Model):
-    id = models.AutoField(primary_key=True, db_column='id')
-    personne = models.ForeignKey('Personne', db_column='personne', editable=False)
+class Chercheur(Personne):
     nationalite = models.ForeignKey(Pays, null = True, db_column='nationalite', to_field='code', 
                                     verbose_name = 'nationalité', related_name='nationalite')
-    #fonction = models.CharField(max_length=36, choices=FONCTION_CHOICES)
     statut = models.CharField(max_length=36, choices=STATUT_CHOICES)
     diplome = models.CharField(max_length=255, null=True, verbose_name = 'diplôme le plus élevé')
     etablissement = models.ForeignKey(Etablissement, db_column='etablissement', null=True, blank=True)
@@ -179,7 +172,7 @@ class Chercheur(models.Model):
     all_objects = models.Manager()
 
     def __unicode__(self):
-        return u"%s %s" % (self.personne.nom.upper(), self.personne.prenom.title())
+        return u"%s %s" % (self.nom.upper(), self.prenom.title())
         
     def statut_display(self):
         for s in STATUT_CHOICES:
index 0fabd3c..0f4ab9e 100644 (file)
@@ -14,7 +14,7 @@ from forms import *
 from django.forms.models import inlineformset_factory
 
 from auf_references_client.models import Discipline, TypeImplantation
-from models import Personne, Utilisateur, Groupe, ChercheurGroupe
+from models import Personne, Groupe, ChercheurGroupe
 
 from django.contrib.auth import authenticate, login
 from django.contrib.auth.decorators import login_required
@@ -35,7 +35,7 @@ def send_password(request):
     if request.method == "POST":
         form = SendPasswordForm(data=request.POST)
         if form.is_valid():
-            u = Utilisateur.objects.get(courriel=form.cleaned_data['email'], actif=True)
+            u = Personne.objects.get(courriel=form.cleaned_data['email'])
             code = u.get_new_password_code()
             link = "%s/accounts/new_password/%s/%s/" % (settings.SITE_ROOT_URL, u.courriel, code)
 
@@ -60,7 +60,7 @@ def send_password(request):
             context_instance = RequestContext(request))
             
 def new_password(request, email, code):
-    u = Utilisateur.objects.get(courriel=email, actif=True)
+    u = Personne.objects.get(courriel=email)
     original_code = u.get_new_password_code()
     message=""
     if(code == original_code):
@@ -84,7 +84,7 @@ def new_password(request, email, code):
 @login_required()            
 def change_password(request):
     context_instance = RequestContext(request)
-    u = context_instance['user_sep']
+    u = context_instance['user_chercheur']
     message = ""
     if request.method == "POST":
         form = NewPasswordForm(data=request.POST)
@@ -120,7 +120,7 @@ def chercheur_login(request):
 def index(request):
     """Répertoire des chercheurs"""
     search_form = RepertoireSearchForm(request.GET)
-    chercheurs = search_form.get_query_set().select_related('personne', 'etablissement')
+    chercheurs = search_form.get_query_set().select_related('etablissement')
     sort = request.GET.get('tri')
     if sort is not None and sort.endswith('_desc'):
         sort = sort[:-5]
@@ -128,7 +128,7 @@ def index(request):
     else:
         direction = ''
     if sort == 'nom':
-        chercheurs = chercheurs.order_by(direction + 'personne__nom', 'personne__prenom', '-date_modification')
+        chercheurs = chercheurs.order_by(direction + 'nom', 'prenom', '-date_modification')
     elif sort == 'etablissement':
         chercheurs = chercheurs.extra(select=dict(nom_etablissement='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
                                       order_by=[direction + 'nom_etablissement', '-date_modification'])
@@ -150,8 +150,8 @@ def inscription(request):
         if forms.is_valid():
             forms.save()
             # login automatique
-            login(request, authenticate(username=forms.personne.cleaned_data['courriel'], 
-                                        password=forms.personne.cleaned_data['password']))
+            login(request, authenticate(username=forms.chercheur.cleaned_data['courriel'], 
+                                        password=forms.chercheur.cleaned_data['password']))
             return HttpResponseRedirect(url('chercheurs.views.perso'))
     else:
         forms = ChercheurFormGroup()
@@ -164,14 +164,14 @@ def inscription(request):
 def desinscription(request):
     """Désinscription du chercheur"""
     try:
-        chercheur = Chercheur.objects.get(personne__courriel=request.user.email, personne__actif=True)
+        chercheur = Chercheur.objects.get(courriel=request.user.email, actif=True)
     except Chercheur.DoesNotExist:
         return HttpResponseRedirect(url('chercheurs.views.chercheur_login'))
     if request.method == 'POST':
         if request.POST.get('confirmer'):
-            chercheur.personne.actif = False
-            chercheur.personne.save()
-            User.objects.filter(username=chercheur.personne.courriel).delete()
+            chercheur.actif = False
+            chercheur.save()
+            User.objects.filter(username=chercheur.courriel).delete()
             request.flash['message'] = "Vous avez été désinscrit du répertoire des chercheurs."
             return HttpResponseRedirect(url('django.contrib.auth.views.logout'))
         else:
index 025fcb5..8e043be 100644 (file)
@@ -1,19 +1,16 @@
 # -*- encoding: utf-8 -*-
 
 import re
-from chercheurs.models import Chercheur, Utilisateur
+from chercheurs.models import Chercheur
     
 def user_chercheur(request):
     user_chercheur = Chercheur.objects.none()
-    user_sep = Utilisateur.objects.none()
     if request.user.is_authenticated():
         try:
-            user_chercheur = Chercheur.objects.get(personne__courriel=request.user.email, personne__actif=True)
-            user_sep = Utilisateur.objects.get(id=user_chercheur.personne_id)
+            user_chercheur = Chercheur.objects.get(courriel=request.user.email)
         except:
             pass
-    return {'user_chercheur': user_chercheur,
-            'user_sep': user_sep,}
+    return {'user_chercheur': user_chercheur}
 
 DISCIPLINE_REGION_RE = re.compile(r'/(discipline/(?P<discipline>\d+)/)?(region/(?P<region>\d+)/)?')
 def discipline_region(request):
diff --git a/auf_savoirs_en_partage/sql/2010-12-07.sql b/auf_savoirs_en_partage/sql/2010-12-07.sql
new file mode 100644 (file)
index 0000000..9ad1c3e
--- /dev/null
@@ -0,0 +1,34 @@
+-- Ramenons le mot de passe dans la fiche personne
+
+ALTER TABLE chercheurs_personne ADD COLUMN password varchar(35) NOT NULL;
+
+UPDATE chercheurs_personne p INNER JOIN chercheurs_utilisateur u ON u.personne_ptr_id = p.id
+SET p.password = u.password;
+
+DROP TABLE chercheurs_utilisateur;
+
+-- Utilisons l'héritage Django pour garder un lien entre le chercheur et la
+-- personne.
+ALTER TABLE chercheurs_chercheur CHANGE COLUMN personne personne_ptr_id integer NOT NULL;
+
+UPDATE chercheurs_chercheurgroupe cg 
+INNER JOIN chercheurs_chercheur c ON c.id = cg.chercheur
+SET cg.chercheur = c.personne_ptr_id;
+
+UPDATE chercheurs_expertise ce 
+INNER JOIN chercheurs_chercheur c ON c.id = ce.chercheur_id
+SET ce.chercheur_id = c.personne_ptr_id;
+
+UPDATE chercheurs_publication cp 
+INNER JOIN chercheurs_chercheur c ON c.id = cp.chercheur_id
+SET cp.chercheur_id = c.personne_ptr_id;
+
+ALTER TABLE chercheurs_these DROP PRIMARY KEY;
+UPDATE chercheurs_these t 
+INNER JOIN chercheurs_chercheur c ON c.id = t.chercheur_id
+SET t.chercheur_id = c.personne_ptr_id;
+ALTER TABLE chercheurs_these ADD PRIMARY KEY (chercheur_id);
+
+ALTER TABLE chercheurs_chercheur 
+    DROP COLUMN id,
+    ADD PRIMARY KEY (personne_ptr_id);
index 936323e..305fbea 100644 (file)
@@ -5,9 +5,16 @@
 {% endif %}   
 <fieldset class="horizontal-radio-buttons">
     <legend>Informations personnelles</legend>
-    {% with forms.personne as form %}
-    {% include "table_form.html" %}
-    {% endwith %}
+    <table>
+        {% form_field forms.chercheur.nom %}
+        {% form_field forms.chercheur.prenom %}
+        {% form_field forms.chercheur.courriel %}
+        {% form_field forms.chercheur.genre %}
+        {% if forms.chercheur.password %}
+        {% form_field forms.chercheur.password %}
+        {% form_field forms.chercheur.password_confirmation %}
+        {% endif %}
+    </table>
 </fieldset>
 
 <fieldset>
index 9ec4650..8abfe92 100644 (file)
@@ -6,7 +6,7 @@
 {% endblock %}
 
 {% block contenu %}
-<h1>{{chercheur.personne.prenom}} {{chercheur.personne.nom}}</h1>
+<h1>{{ chercheur.prenom }} {{ chercheur.nom }}</h1>
 <form method="post" action="">
     {% include "chercheurs/chercheur_form.html" %}    
     <input type="submit" value="Sauvegarder" />
index 338a77d..d2135b5 100644 (file)
@@ -1,6 +1,6 @@
 <div id="fiche_chercheur">
 
-    <div><a href="mailto:{{ chercheur.personne.courriel }}">{{ chercheur.personne.courriel }}</a></div>
+    <div><a href="mailto:{{ chercheur.courriel }}">{{ chercheur.courriel }}</a></div>
     <div>{{ chercheur.etablissement_display }}</div>
     <div><span class="label">Région: </span>{{ chercheur.region.nom }}</div>