From 1e5c55a54020a8261f70ea125200c8a980fc9603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sat, 4 Feb 2017 11:57:58 +0100 Subject: [PATCH 1/7] update readme --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e7056f1e..bba1e66c 100644 --- a/README.md +++ b/README.md @@ -84,29 +84,30 @@ visualiser la dernière version du code. Si vous optez pour une installation manuelle plutôt que d'utiliser Vagrant, il est fortement conseillé d'utiliser un environnement virtuel pour Python. -Il vous faudra installer mercurial, pip, les librairies de développement de -python, un client et un serveur MySQL ainsi qu'un serveur redis ; sous Debian et -dérivées (Ubuntu, ...) : +Il vous faudra installer pip, les librairies de développement de python, un +client et un serveur MySQL ainsi qu'un serveur redis ; sous Debian et dérivées +(Ubuntu, ...) : - sudo apt-get install mercurial python-pip python-dev libmysqlclient-dev - redis-server + sudo apt-get install python-pip python-dev libmysqlclient-dev redis-server Si vous décidez d'utiliser un environnement virtuel Python (virtualenv; fortement conseillé), déplacez-vous dans le dossier où est installé GestioCOF (le dossier où se trouve ce README), et créez-le maintenant : - virtualenv env + virtualenv env -p $(which python3) -Pour l'activer, il faut faire +L'option `-p` sert à préciser l'exécutable python à utiliser. Vous devez choisir +python3, si c'est la version de python par défaut sur votre système, ceci n'est +pas nécessaire. Pour l'activer, il faut faire . env/bin/activate dans le même dossier. -Vous pouvez maintenant installer les dépendances Python depuis les fichiers -`requirements.txt` et `requirements-devel.txt` : +Vous pouvez maintenant installer les dépendances Python depuis le fichier +`requirements-devel.txt` : - pip install -r requirements.txt -r requirements-devel.txt + pip install -r requirements-devel.txt Copiez le fichier `cof/settings_dev.py` dans `cof/settings.py`. From bb4e9dde4f0aa88f3fa6017e5e0f4b4662c080a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Feb 2017 13:32:31 +0100 Subject: [PATCH 2/7] End of py2 support --- gestioncof/petits_cours_models.py | 11 +---------- gestioncof/petits_cours_views.py | 4 ---- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index 4428b78c..7e4f4165 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -1,14 +1,10 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals +from functools import reduce from django.db import models from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ -from django.utils.encoding import python_2_unicode_compatible -from django.utils.six.moves import reduce def choices_length(choices): @@ -24,7 +20,6 @@ LEVELS_CHOICES = ( ) -@python_2_unicode_compatible class PetitCoursSubject(models.Model): name = models.CharField(_("Matière"), max_length=30) users = models.ManyToManyField(User, related_name="petits_cours_matieres", @@ -38,7 +33,6 @@ class PetitCoursSubject(models.Model): return self.name -@python_2_unicode_compatible class PetitCoursAbility(models.Model): user = models.ForeignKey(User) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matière")) @@ -56,7 +50,6 @@ class PetitCoursAbility(models.Model): self.matiere, self.niveau) -@python_2_unicode_compatible class PetitCoursDemande(models.Model): name = models.CharField(_("Nom/prénom"), max_length=200) email = models.CharField(_("Adresse email"), max_length=300) @@ -103,7 +96,6 @@ class PetitCoursDemande(models.Model): self.created.strftime("%d %b %Y")) -@python_2_unicode_compatible class PetitCoursAttribution(models.Model): user = models.ForeignKey(User) demande = models.ForeignKey(PetitCoursDemande, verbose_name=_("Demande")) @@ -122,7 +114,6 @@ class PetitCoursAttribution(models.Model): % (self.demande.id, self.user.username, self.matiere) -@python_2_unicode_compatible class PetitCoursAttributionCounter(models.Model): user = models.ForeignKey(User) matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere")) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index ee71d1a9..40b0feb9 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,9 +1,5 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.shortcuts import render, get_object_or_404, redirect from django.core import mail from django.core.mail import EmailMessage From 2bc5f3d64666da1e004caa6aeda8b7c26a77fbc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Feb 2017 13:49:01 +0100 Subject: [PATCH 3/7] Style and PEP8 - Drop `%` in favour of `.format` which has a better specification - Remove a string concatenation - Remove the trailing slashes according to the PEP8: https://www.python.org/dev/peps/pep-0008/#maximum-line-length NB. We let some which will disappear in the next commit. - Remove an unused import and change the imports order --- gestioncof/petits_cours_models.py | 22 +++++++++------- gestioncof/petits_cours_views.py | 42 +++++++++++++++++-------------- 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index 7e4f4165..6d9dac82 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -46,8 +46,9 @@ class PetitCoursAbility(models.Model): verbose_name_plural = "Compétences des petits cours" def __str__(self): - return "%s - %s - %s" % (self.user.username, - self.matiere, self.niveau) + return "{:s} - {!s} - {:s}".format( + self.user.username, self.matiere, self.niveau + ) class PetitCoursDemande(models.Model): @@ -63,7 +64,7 @@ class PetitCoursDemande(models.Model): freq = models.CharField( _("Fréquence"), help_text=_("Indiquez ici la fréquence envisagée " - + "(hebdomadaire, 2 fois par semaine, ...)"), + "(hebdomadaire, 2 fois par semaine, ...)"), max_length=300, blank=True) lieu = models.CharField( _("Lieu (si préférence)"), @@ -92,8 +93,9 @@ class PetitCoursDemande(models.Model): verbose_name_plural = "Demandes de petits cours" def __str__(self): - return "Demande %d du %s" % (self.id, - self.created.strftime("%d %b %Y")) + return "Demande {:d} du {:s}".format( + self.id, self.created.strftime("%d %b %Y") + ) class PetitCoursAttribution(models.Model): @@ -110,8 +112,9 @@ class PetitCoursAttribution(models.Model): verbose_name_plural = "Attributions de petits cours" def __str__(self): - return "Attribution de la demande %d à %s pour %s" \ - % (self.demande.id, self.user.username, self.matiere) + return "Attribution de la demande {:d} à {:s} pour {!s}".format( + self.demande.id, self.user.username, self.matiere + ) class PetitCoursAttributionCounter(models.Model): @@ -124,5 +127,6 @@ class PetitCoursAttributionCounter(models.Model): verbose_name_plural = "Compteurs d'attributions de petits cours" def __str__(self): - return "%d demandes envoyées à %s pour %s" \ - % (self.count, self.user.username, self.matiere) + return "{:d} demandes envoyées à {:s} pour {!s}".format( + self.count, self.user.username, self.matiere + ) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 40b0feb9..f9a038a7 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -1,5 +1,8 @@ # -*- coding: utf-8 -*- +import json +from datetime import datetime + from django.shortcuts import render, get_object_or_404, redirect from django.core import mail from django.core.mail import EmailMessage @@ -16,18 +19,15 @@ from django.contrib.auth.decorators import login_required from django.db.models import Min from gestioncof.models import CofProfile -from gestioncof.petits_cours_models import PetitCoursDemande, \ - PetitCoursAttribution, PetitCoursAttributionCounter, PetitCoursAbility, \ - PetitCoursSubject +from gestioncof.petits_cours_models import ( + PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter, + PetitCoursAbility, PetitCoursSubject +) from gestioncof.decorators import buro_required from gestioncof.shared import lock_table, unlock_tables from captcha.fields import ReCaptchaField -from datetime import datetime -import base64 -import json - class DemandeListView(ListView): model = PetitCoursDemande @@ -174,17 +174,19 @@ def _traitement_other_preparing(request, demande): proposals[matiere] = [] for choice_id in range(min(3, len(candidates))): choice = int( - request.POST["proposal-%d-%d" % (matiere.id, choice_id)]) + request.POST["proposal-{:d}-{:d}" + .format(matiere.id, choice_id)] + ) if choice == -1: continue if choice not in candidates: - errors.append("Choix invalide pour la proposition %d" - "en %s" % (choice_id + 1, matiere)) + errors.append("Choix invalide pour la proposition {:d}" + "en {!s}".format(choice_id + 1, matiere)) continue user = candidates[choice] if user in proposals[matiere]: - errors.append("La proposition %d en %s est un doublon" - % (choice_id + 1, matiere)) + errors.append("La proposition {:d} en {!s} est un doublon" + .format(choice_id + 1, matiere)) continue proposals[matiere].append(user) attribdata[matiere.id].append(user.id) @@ -193,12 +195,13 @@ def _traitement_other_preparing(request, demande): else: proposed_for[user].append(matiere) if not proposals[matiere]: - errors.append("Aucune proposition pour %s" % (matiere,)) + errors.append("Aucune proposition pour {!s}".format(matiere)) elif len(proposals[matiere]) < 3: - errors.append("Seulement %d proposition%s pour %s" - % (len(proposals[matiere]), - "s" if len(proposals[matiere]) > 1 else "", - matiere)) + errors.append("Seulement {:d} proposition{:s} pour {!s}" + .format( + len(proposals[matiere]), + "s" if len(proposals[matiere]) > 1 else "", + matiere)) else: unsatisfied.append(matiere) return _finalize_traitement(request, demande, proposals, proposed_for, @@ -350,8 +353,9 @@ def inscription(request): profile.save() lock_table(PetitCoursAttributionCounter, PetitCoursAbility, User, PetitCoursSubject) - abilities = PetitCoursAbility.objects \ - .filter(user=request.user).all() + abilities = ( + PetitCoursAbility.objects.filter(user=request.user).all() + ) for ability in abilities: _get_attrib_counter(ability.user, ability.matiere) unlock_tables() From 81681ad0e567e4565a3c4ed1e1a9f208ea153d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Feb 2017 17:07:58 +0100 Subject: [PATCH 4/7] Turn 2 functions into class/objects methods - `_get_attrib_counter` become a classmethod of `PetitCoursAttributionCounter` - `_get_demande_candidates` become a method of `PetitCoursDemande` --- gestioncof/petits_cours_models.py | 46 ++++++++++++++++++++++++++++ gestioncof/petits_cours_views.py | 51 +++++++++---------------------- 2 files changed, 61 insertions(+), 36 deletions(-) diff --git a/gestioncof/petits_cours_models.py b/gestioncof/petits_cours_models.py index 6d9dac82..753e8674 100644 --- a/gestioncof/petits_cours_models.py +++ b/gestioncof/petits_cours_models.py @@ -3,6 +3,7 @@ from functools import reduce from django.db import models +from django.db.models import Min from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ @@ -88,6 +89,32 @@ class PetitCoursDemande(models.Model): blank=True, null=True) created = models.DateTimeField(_("Date de création"), auto_now_add=True) + def get_candidates(self, redo=False): + """ + Donne la liste des profs disponibles pour chaque matière de la demande. + - On ne donne que les agrégés si c'est demandé + - Si ``redo`` vaut ``True``, cela signifie qu'on retraite la demande et + il ne faut pas proposer à nouveau des noms qui ont déjà été proposés + """ + for matiere in self.matieres.all(): + candidates = PetitCoursAbility.objects.filter( + matiere=matiere, + niveau=self.niveau, + user__profile__is_cof=True, + user__profile__petits_cours_accept=True + ) + if self.agrege_requis: + candidates = candidates.filter(agrege=True) + if redo: + attrs = self.petitcoursattribution_set.filter(matiere=matiere) + already_proposed = [ + attr.user + for attr in attrs + ] + candidates = candidates.exclude(user__in=already_proposed) + candidates = candidates.order_by('?').select_related().all() + yield (matiere, candidates) + class Meta: verbose_name = "Demande de petits cours" verbose_name_plural = "Demandes de petits cours" @@ -122,6 +149,25 @@ class PetitCoursAttributionCounter(models.Model): matiere = models.ForeignKey(PetitCoursSubject, verbose_name=_("Matiere")) count = models.IntegerField("Nombre d'envois", default=0) + @classmethod + def get_uptodate(cls, user, matiere): + """ + Donne le compteur de l'utilisateur pour cette matière. Si le compteur + n'existe pas encore, il est initialisé avec le minimum des valeurs des + compteurs de tout le monde. + """ + counter, created = cls.objects.get_or_create( + user=user, matiere=matiere) + if created: + mincount = ( + cls.objects.filter(matiere=matiere).exclude(user=user) + .aggregate(Min('count')) + ['count__min'] + ) + counter.count = mincount + counter.save() + return counter + class Meta: verbose_name = "Compteur d'attribution de petits cours" verbose_name_plural = "Compteurs d'attributions de petits cours" diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index f9a038a7..68befaf7 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -16,7 +16,6 @@ from django.views.decorators.csrf import csrf_exempt from django.template import loader from django.conf import settings from django.contrib.auth.decorators import login_required -from django.db.models import Min from gestioncof.models import CofProfile from gestioncof.petits_cours_models import ( @@ -51,35 +50,6 @@ def details(request, demande_id): "attributions": attributions}) -def _get_attrib_counter(user, matiere): - counter, created = PetitCoursAttributionCounter \ - .objects.get_or_create(user=user, matiere=matiere) - if created: - mincount = PetitCoursAttributionCounter.objects \ - .filter(matiere=matiere).exclude(user=user).all() \ - .aggregate(Min('count')) - counter.count = mincount['count__min'] - counter.save() - return counter - - -def _get_demande_candidates(demande, redo=False): - for matiere in demande.matieres.all(): - candidates = PetitCoursAbility.objects.filter(matiere=matiere, - niveau=demande.niveau) - candidates = candidates.filter(user__profile__is_cof=True, - user__profile__petits_cours_accept=True) - if demande.agrege_requis: - candidates = candidates.filter(agrege=True) - if redo: - attributions = PetitCoursAttribution.objects \ - .filter(demande=demande, matiere=matiere).all() - for attrib in attributions: - candidates = candidates.exclude(user=attrib.user) - candidates = candidates.order_by('?').select_related().all() - yield (matiere, candidates) - - @buro_required def traitement(request, demande_id, redo=False): demande = get_object_or_404(PetitCoursDemande, id=demande_id) @@ -91,12 +61,15 @@ def traitement(request, demande_id, redo=False): proposed_for = {} unsatisfied = [] attribdata = {} - for matiere, candidates in _get_demande_candidates(demande, redo): + for matiere, candidates in demande.get_candidates(redo): if candidates: tuples = [] for candidate in candidates: user = candidate.user - tuples.append((candidate, _get_attrib_counter(user, matiere))) + tuples.append(( + candidate, + PetitCoursAttributionCounter.get_uptodate(user, matiere) + )) tuples = sorted(tuples, key=lambda c: c[1].count) candidates, _ = zip(*tuples) candidates = candidates[0:min(3, len(candidates))] @@ -166,7 +139,7 @@ def _traitement_other_preparing(request, demande): proposed_for = {} attribdata = {} errors = [] - for matiere, candidates in _get_demande_candidates(demande, redo): + for matiere, candidates in demande.get_candidates(redo): if candidates: candidates = dict([(candidate.user.id, candidate.user) for candidate in candidates]) @@ -218,12 +191,15 @@ def _traitement_other(request, demande, redo): proposed_for = {} unsatisfied = [] attribdata = {} - for matiere, candidates in _get_demande_candidates(demande, redo): + for matiere, candidates in demande.get_candidates(redo): if candidates: tuples = [] for candidate in candidates: user = candidate.user - tuples.append((candidate, _get_attrib_counter(user, matiere))) + tuples.append(( + candidate, + PetitCoursAttributionCounter.get_uptodate(user, matiere) + )) tuples = sorted(tuples, key=lambda c: c[1].count) candidates, _ = zip(*tuples) attribdata[matiere.id] = [] @@ -357,7 +333,10 @@ def inscription(request): PetitCoursAbility.objects.filter(user=request.user).all() ) for ability in abilities: - _get_attrib_counter(ability.user, ability.matiere) + PetitCoursAttributionCounter.get_uptodate( + ability.user, + ability.matiere + ) unlock_tables() success = True formset = MatieresFormSet(instance=request.user) From 9aa4782d5733b6c83cf1641a8cbcee76e4338ad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Feb 2017 17:10:51 +0100 Subject: [PATCH 5/7] Move petits-cours forms in another file --- gestioncof/petits_cours_forms.py | 54 ++++++++++++++++++++++++++++++++ gestioncof/petits_cours_views.py | 46 +-------------------------- 2 files changed, 55 insertions(+), 45 deletions(-) create mode 100644 gestioncof/petits_cours_forms.py diff --git a/gestioncof/petits_cours_forms.py b/gestioncof/petits_cours_forms.py new file mode 100644 index 00000000..dfb7a263 --- /dev/null +++ b/gestioncof/petits_cours_forms.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +from captcha.fields import ReCaptchaField + +from django import forms +from django.forms import ModelForm +from django.forms.models import inlineformset_factory, BaseInlineFormSet +from django.contrib.auth.models import User + +from gestioncof.petits_cours_models import PetitCoursDemande, PetitCoursAbility + + +class BaseMatieresFormSet(BaseInlineFormSet): + def clean(self): + super(BaseMatieresFormSet, self).clean() + if any(self.errors): + # Don't bother validating the formset unless each form is + # valid on its own + return + matieres = [] + for i in range(0, self.total_form_count()): + form = self.forms[i] + if not form.cleaned_data: + continue + matiere = form.cleaned_data['matiere'] + niveau = form.cleaned_data['niveau'] + delete = form.cleaned_data['DELETE'] + if not delete and (matiere, niveau) in matieres: + raise forms.ValidationError( + "Vous ne pouvez pas vous inscrire deux fois pour la " + "même matiere avec le même niveau.") + matieres.append((matiere, niveau)) + + +class DemandeForm(ModelForm): + captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'}) + + def __init__(self, *args, **kwargs): + super(DemandeForm, self).__init__(*args, **kwargs) + self.fields['matieres'].help_text = '' + + class Meta: + model = PetitCoursDemande + fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu', + 'matieres', 'agrege_requis', 'niveau', 'remarques') + widgets = {'matieres': forms.CheckboxSelectMultiple} + + +MatieresFormSet = inlineformset_factory( + User, + PetitCoursAbility, + fields=("matiere", "niveau", "agrege"), + formset=BaseMatieresFormSet +) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 68befaf7..ec32358d 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -6,9 +6,6 @@ from datetime import datetime from django.shortcuts import render, get_object_or_404, redirect from django.core import mail from django.core.mail import EmailMessage -from django.forms import ModelForm -from django import forms -from django.forms.models import inlineformset_factory, BaseInlineFormSet from django.contrib.auth.models import User from django.views.generic import ListView from django.utils.decorators import method_decorator @@ -22,11 +19,10 @@ from gestioncof.petits_cours_models import ( PetitCoursDemande, PetitCoursAttribution, PetitCoursAttributionCounter, PetitCoursAbility, PetitCoursSubject ) +from gestioncof.petits_cours_forms import DemandeForm, MatieresFormSet from gestioncof.decorators import buro_required from gestioncof.shared import lock_table, unlock_tables -from captcha.fields import ReCaptchaField - class DemandeListView(ListView): model = PetitCoursDemande @@ -288,37 +284,11 @@ def _traitement_post(request, demande): }) -class BaseMatieresFormSet(BaseInlineFormSet): - def clean(self): - super(BaseMatieresFormSet, self).clean() - if any(self.errors): - # Don't bother validating the formset unless each form is - # valid on its own - return - matieres = [] - for i in range(0, self.total_form_count()): - form = self.forms[i] - if not form.cleaned_data: - continue - matiere = form.cleaned_data['matiere'] - niveau = form.cleaned_data['niveau'] - delete = form.cleaned_data['DELETE'] - if not delete and (matiere, niveau) in matieres: - raise forms.ValidationError( - "Vous ne pouvez pas vous inscrire deux fois pour la " - "même matiere avec le même niveau.") - matieres.append((matiere, niveau)) - - @login_required def inscription(request): profile, created = CofProfile.objects.get_or_create(user=request.user) if not profile.is_cof: return redirect("cof-denied") - MatieresFormSet = inlineformset_factory(User, PetitCoursAbility, - fields=("matiere", "niveau", - "agrege",), - formset=BaseMatieresFormSet) success = False if request.method == "POST": formset = MatieresFormSet(request.POST, instance=request.user) @@ -348,20 +318,6 @@ def inscription(request): "remarques": profile.petits_cours_remarques}) -class DemandeForm(ModelForm): - captcha = ReCaptchaField(attrs={'theme': 'clean', 'lang': 'fr'}) - - def __init__(self, *args, **kwargs): - super(DemandeForm, self).__init__(*args, **kwargs) - self.fields['matieres'].help_text = '' - - class Meta: - model = PetitCoursDemande - fields = ('name', 'email', 'phone', 'quand', 'freq', 'lieu', - 'matieres', 'agrege_requis', 'niveau', 'remarques') - widgets = {'matieres': forms.CheckboxSelectMultiple} - - @csrf_exempt def demande(request): success = False From 45eb384cfd6c096d53e4b9e94ee96e15fff15800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20P=C3=A9pin?= Date: Sun, 5 Feb 2017 17:35:41 +0100 Subject: [PATCH 6/7] Use class-based views See #94 --- gestioncof/petits_cours_views.py | 21 ++++++++----------- .../details_demande_petit_cours.html | 14 ++++++------- gestioncof/urls.py | 14 ++++++------- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index ec32358d..3228ccd1 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -7,8 +7,7 @@ from django.shortcuts import render, get_object_or_404, redirect from django.core import mail from django.core.mail import EmailMessage from django.contrib.auth.models import User -from django.views.generic import ListView -from django.utils.decorators import method_decorator +from django.views.generic import ListView, DetailView from django.views.decorators.csrf import csrf_exempt from django.template import loader from django.conf import settings @@ -32,18 +31,16 @@ class DemandeListView(ListView): def get_queryset(self): return PetitCoursDemande.objects.order_by('traitee', '-id').all() - @method_decorator(buro_required) - def dispatch(self, *args, **kwargs): - return super(DemandeListView, self).dispatch(*args, **kwargs) +class DemandeDetailView(DetailView): + model = PetitCoursDemande + template_name = "details_demande_petit_cours.html" -@buro_required -def details(request, demande_id): - demande = get_object_or_404(PetitCoursDemande, id=demande_id) - attributions = PetitCoursAttribution.objects.filter(demande=demande).all() - return render(request, "details_demande_petit_cours.html", - {"demande": demande, - "attributions": attributions}) + def get_context_data(self, **kwargs): + context = super(DemandeDetailView, self).get_context_data(**kwargs) + obj = context['object'] + context['attributions'] = obj.petitcoursattribution_set.all() + return context @buro_required diff --git a/gestioncof/templates/details_demande_petit_cours.html b/gestioncof/templates/details_demande_petit_cours.html index b51c0dc0..1a0ed240 100644 --- a/gestioncof/templates/details_demande_petit_cours.html +++ b/gestioncof/templates/details_demande_petit_cours.html @@ -8,10 +8,10 @@ {% include "details_demande_petit_cours_infos.html" %}
- - {% if demande.traitee %} - - + + {% if object.traitee %} + + {% endif %}
Traitée
Traitée par {{ demande.traitee_par }}
Traitée le {{ demande.processed }}
Traitée
Traitée par {{ object.traitee_par }}
Traitée le {{ object.processed }}
Attributions
    @@ -23,15 +23,15 @@
- {% if demande.traitee %} + {% if object.traitee %}
-
+
{% else %}
-
+
diff --git a/gestioncof/urls.py b/gestioncof/urls.py index ad108005..9a562e7e 100644 --- a/gestioncof/urls.py +++ b/gestioncof/urls.py @@ -1,12 +1,9 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django.conf.urls import url -from gestioncof.petits_cours_views import DemandeListView +from gestioncof.petits_cours_views import DemandeListView, DemandeDetailView from gestioncof import views, petits_cours_views +from gestioncof.decorators import buro_required export_patterns = [ url(r'^members$', views.export_members), @@ -24,10 +21,11 @@ petitcours_patterns = [ name='petits-cours-demande'), url(r'^demande-raw$', petits_cours_views.demande_raw, name='petits-cours-demande-raw'), - url(r'^demandes$', DemandeListView.as_view(), + url(r'^demandes$', + buro_required(DemandeListView.as_view()), name='petits-cours-demandes-list'), - url(r'^demandes/(?P\d+)$', - petits_cours_views.details, + url(r'^demandes/(?P\d+)$', + buro_required(DemandeDetailView.as_view()), name='petits-cours-demande-details'), url(r'^demandes/(?P\d+)/traitement$', petits_cours_views.traitement, From ed01508481d5c8496d68fd39f4b49fafd376d7f6 Mon Sep 17 00:00:00 2001 From: Qwann Date: Sat, 11 Feb 2017 02:51:43 +0100 Subject: [PATCH 7/7] using context_object_name and moving template --- gestioncof/petits_cours_views.py | 5 +++-- .../details_demande_petit_cours.html | 14 +++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) rename gestioncof/templates/{ => gestioncof}/details_demande_petit_cours.html (70%) diff --git a/gestioncof/petits_cours_views.py b/gestioncof/petits_cours_views.py index 3228ccd1..503dcdb3 100644 --- a/gestioncof/petits_cours_views.py +++ b/gestioncof/petits_cours_views.py @@ -34,11 +34,12 @@ class DemandeListView(ListView): class DemandeDetailView(DetailView): model = PetitCoursDemande - template_name = "details_demande_petit_cours.html" + template_name = "gestioncof/details_demande_petit_cours.html" + context_object_name = "demande" def get_context_data(self, **kwargs): context = super(DemandeDetailView, self).get_context_data(**kwargs) - obj = context['object'] + obj = self.object context['attributions'] = obj.petitcoursattribution_set.all() return context diff --git a/gestioncof/templates/details_demande_petit_cours.html b/gestioncof/templates/gestioncof/details_demande_petit_cours.html similarity index 70% rename from gestioncof/templates/details_demande_petit_cours.html rename to gestioncof/templates/gestioncof/details_demande_petit_cours.html index 1a0ed240..b51c0dc0 100644 --- a/gestioncof/templates/details_demande_petit_cours.html +++ b/gestioncof/templates/gestioncof/details_demande_petit_cours.html @@ -8,10 +8,10 @@ {% include "details_demande_petit_cours_infos.html" %}
- - {% if object.traitee %} - - + + {% if demande.traitee %} + + {% endif %}
Traitée
Traitée par {{ object.traitee_par }}
Traitée le {{ object.processed }}
Traitée
Traitée par {{ demande.traitee_par }}
Traitée le {{ demande.processed }}
Attributions
    @@ -23,15 +23,15 @@
- {% if object.traitee %} + {% if demande.traitee %}
-
+
{% else %}
-
+