From 780b475d412aea778dbd18c3f82ede2088239dd7 Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Wed, 7 Nov 2012 17:45:53 +0100 Subject: [PATCH] Improved attribution template and adapted data model --- common/urls.py | 5 +- docs/SchemaRelationnel.odg | Bin 18726 -> 18771 bytes stages/admin.py | 10 ++- stages/fixtures/test_fixture.json | 76 ++++++++++++++------- stages/models.py | 19 ++++-- stages/views.py | 49 +++++++++----- templates/admin/index.html | 5 +- templates/attribution.html | 100 +++++++++++++++++++++------- templates/availability_summary.html | 6 ++ templates/corporation_summary.html | 5 -- templates/trainings_list.html | 3 + 11 files changed, 196 insertions(+), 82 deletions(-) create mode 100644 templates/availability_summary.html delete mode 100644 templates/corporation_summary.html create mode 100644 templates/trainings_list.html diff --git a/common/urls.py b/common/urls.py index 693382a..f94dfd6 100644 --- a/common/urls.py +++ b/common/urls.py @@ -21,10 +21,11 @@ urlpatterns = patterns('', # AJAX/JSON urls url(r'^section/(?P\d+)/periods/', 'stages.views.section_periods'), url(r'^period/(?P\d+)/students/', 'stages.views.period_students'), - url(r'^period/(?P\d+)/corporations/', 'stages.views.period_corporations'), + url(r'^period/(?P\d+)/corporations/', 'stages.views.period_availabilities'), # Training params in POST: url(r'^training/new/', 'stages.views.new_training'), + url(r'^training/by_period/(?P\d+)/', views.TrainingsByPeriodView.as_view()), url(r'^student/(?P\d+)/summary/', views.StudentSummaryView.as_view()), - url(r'^corporation/(?P\d+)/summary/', views.CorporationSummaryView.as_view()), + url(r'^availability/(?P\d+)/summary/', views.AvailabilitySummaryView.as_view()), ) diff --git a/docs/SchemaRelationnel.odg b/docs/SchemaRelationnel.odg index 464c146b8c378ececdc6ef8908200fa8978b9d1c..08fc5a56d7277d90cdd4077cef3b85f142340451 100644 GIT binary patch delta 13799 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 N(PhzL;UxcB{Vz>|^}YZA delta 13748 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 Vc#wF)xHwLNpe!o%vc%up|39Qf6{`RM diff --git a/stages/admin.py b/stages/admin.py index c52e445..7c20148 100644 --- a/stages/admin.py +++ b/stages/admin.py @@ -25,14 +25,20 @@ class CorporationAdmin(admin.ModelAdmin): inlines = [ContactInline] +class AvailabilityInline(admin.TabularInline): + model = Availability + extra = 1 + class PeriodAdmin(admin.ModelAdmin): list_display = ('dates', 'section') list_filter = ('section',) + inlines = [AvailabilityInline] class AvailabilityAdmin(admin.ModelAdmin): - list_display = ('corporation', 'period', 'number') - fields = (('corporation', 'period'), ('number', 'domain')) + list_display = ('corporation', 'period', 'domain') + list_filter = ('period',) + fields = (('corporation', 'period'), 'domain', 'comment') admin.site.register(Student, StudentAdmin) diff --git a/stages/fixtures/test_fixture.json b/stages/fixtures/test_fixture.json index b2a8745..0a1d01a 100644 --- a/stages/fixtures/test_fixture.json +++ b/stages/fixtures/test_fixture.json @@ -24,48 +24,48 @@ "pk": 1, "model": "stages.student", "fields": { - "birth_date": "1994-05-12", + "city": "La Chaux-de-Fonds", "first_name": "Albin", - "last_name": "Dupond", - "section": 1, - "pcode": "2300", - "city": "La Chaux-de-Fonds" + "last_name": "Dupond", + "section": 1, + "pcode": "2300", + "birth_date": "1994-05-12" } }, { "pk": 2, "model": "stages.student", "fields": { - "birth_date": "1994-07-12", + "city": "Neuch\u00e2tel", "first_name": "Justine", - "last_name": "Varrin", - "section": 1, - "pcode": "2000", - "city": "Neuchâtel" + "last_name": "Varrin", + "section": 1, + "pcode": "2000", + "birth_date": "1994-07-12" } }, { "pk": 3, "model": "stages.student", "fields": { - "birth_date": "1994-05-20", + "city": "Cernier", "first_name": "Elvire", - "last_name": "Hickx", - "section": 1, - "pcode": "2053", - "city": "Cernier" + "last_name": "Hickx", + "section": 1, + "pcode": "2053", + "birth_date": "1994-05-20" } }, { "pk": 4, "model": "stages.student", "fields": { - "birth_date": "1994-10-11", - "first_name": "André", - "last_name": "Allemand", - "section": 1, - "pcode": "2314", - "city": "La Sagne" + "city": "La Sagne", + "first_name": "Andr\u00e9", + "last_name": "Allemand", + "section": 1, + "pcode": "2314", + "birth_date": "1994-10-11" } }, { @@ -88,6 +88,17 @@ "email": "" } }, + { + "pk": 1, + "model": "stages.corpcontact", + "fields": { + "corporation": 1, + "first_name": "Jean", + "last_name": "Horner", + "tel": "", + "email": "" + } + }, { "pk": 1, "model": "stages.domain", @@ -113,13 +124,32 @@ }, { "pk": 1, - "model": "stages.training", + "model": "stages.availability", "fields": { "corporation": 1, "domain": 1, "period": 1, + "comment": "" + } + }, + { + "pk": 2, + "model": "stages.availability", + "fields": { + "corporation": 1, + "domain": 2, + "period": 1, + "comment": "" + } + }, + { + "pk": 1, + "model": "stages.training", + "fields": { + "availability": 1, "student": 1, - "referent": 1 + "referent": 1, + "comment": "" } } ] diff --git a/stages/models.py b/stages/models.py index 578c4be..7437bf1 100644 --- a/stages/models.py +++ b/stages/models.py @@ -101,26 +101,33 @@ class Availability(models.Model): """ Disponibilités des institutions """ corporation = models.ForeignKey(Corporation, verbose_name='Institution') period = models.ForeignKey(Period, verbose_name='Période') - number = models.IntegerField(verbose_name='Nombre de places') domain = models.ForeignKey(Domain, verbose_name='Domaine') + comment = models.TextField(blank=True, verbose_name='Remarques') class Meta: verbose_name = "Disponibilité" def __unicode__(self): - return '%d place(s) chez %s (%s)' % (self.number, self.corporation, self.period) + return '%s - %s (%s)' % (self.period, self.corporation, self.domain) + + @property + def free(self): + try: + self.training + except Training.DoesNotExist: + return True + return False class Training(models.Model): """ Stages """ student = models.ForeignKey(Student, verbose_name='Étudiant') - corporation = models.ForeignKey(Corporation, verbose_name='Institution') + availability = models.OneToOneField(Availability, verbose_name='Disponibilité') referent = models.ForeignKey(Referent, verbose_name='Référent') - period = models.ForeignKey(Period, verbose_name='Période') - domain = models.ForeignKey(Domain, verbose_name='Domaine') + comment = models.TextField(blank=True, verbose_name='Remarques') class Meta: verbose_name = "Stage" def __unicode__(self): - return '%s chez %s (%s)' % (self.student, self.corporation, self.period) + return '%s chez %s (%s)' % (self.student, self.availability.corporation, self.availability.period) diff --git a/stages/views.py b/stages/views.py index 8b603fb..2193459 100644 --- a/stages/views.py +++ b/stages/views.py @@ -6,10 +6,10 @@ import json from django.http import HttpResponse, HttpResponseNotAllowed from django.shortcuts import get_object_or_404 from django.views.decorators.csrf import csrf_exempt -from django.views.generic import DetailView, TemplateView +from django.views.generic import DetailView, TemplateView, ListView from .forms import PeriodForm -from .models import Section, Student, Corporation, Period, Training +from .models import Section, Student, Corporation, Period, Training, Referent, Availability class StudentSummaryView(DetailView): @@ -17,9 +17,18 @@ class StudentSummaryView(DetailView): template_name = 'student_summary.html' -class CorporationSummaryView(DetailView): - model = Corporation - template_name = 'corporation_summary.html' +class AvailabilitySummaryView(DetailView): + model = Availability + template_name = 'availability_summary.html' + + +class TrainingsByPeriodView(ListView): + template_name = 'trainings_list.html' + context_object_name = 'trainings' + + def get_queryset(self): + return Training.objects.select_related('student', 'availability__corporation', 'availability__domain' + ).filter(availability__period__pk=self.kwargs['pk']) class AttributionView(TemplateView): @@ -30,6 +39,7 @@ class AttributionView(TemplateView): context.update({ #'period_form': PeriodForm(), 'sections': Section.objects.all(), + 'referents': Referent.objects.all(), }) return context @@ -47,14 +57,14 @@ def period_students(request, pk): """ period = get_object_or_404(Period, pk=pk) students = period.section.student_set.all().order_by('last_name') - trainings = dict((t.student_id, t.id) for t in Training.objects.filter(period=period)) + trainings = dict((t.student_id, t.id) for t in Training.objects.filter(availability__period=period)) data = [{'name': unicode(s), 'id': s.id, 'training_id': trainings.get(s.id)} for s in students] return HttpResponse(json.dumps(data), content_type="application/json") -def period_corporations(request, pk): - """ Return all corporations with availabilities in the specified period """ +def period_availabilities(request, pk): + """ Return all availabilities in the specified period """ period = get_object_or_404(Period, pk=pk) - corps = [(av.corporation.id, av.corporation.name) + corps = [{'id': av.id, 'corp_name': av.corporation.name, 'domain': av.domain.name, 'free': av.free} for av in period.availability_set.select_related('corporation').all()] return HttpResponse(json.dumps(corps), content_type="application/json") @@ -62,11 +72,14 @@ def period_corporations(request, pk): def new_training(request): if request.method != 'POST': return HttpResponseNotAllowed() - training = Training.objects.create( - period=Period.objects.get(pk=request.POST.get('period')), - student=Student.objects.get(pk=request.POST.get('student')), - corporation=Corporation.objects.get(pk=request.POST.get('corp')) - ) + try: + training = Training.objects.create( + student=Student.objects.get(pk=request.POST.get('student')), + availability=Availability.objects.get(pk=request.POST.get('avail')), + referent=Referent.objects.get(pk=request.POST.get('referent')), + ) + except Exception as exc: + return HttpResponse(str(exc)) return HttpResponse('OK') @@ -77,10 +90,10 @@ def stages_export(request): export_fields = [ ('Prénom', 'student__first_name'), ('Nom', 'student__last_name'), - ('Filière', 'period__section__name'), - ('Début', 'period__start_date'), ('Fin', 'period__end_date'), - ('Institution', 'corporation__name'), - ('Domaine', 'domain__name'), + ('Filière', 'student__section__name'), + ('Début', 'availability__period__start_date'), ('Fin', 'availability__period__end_date'), + ('Institution', 'availability__corporation__name'), + ('Domaine', 'availability__domain__name'), ('Prénom référent', 'referent__first_name'), ('Nom référent', 'referent__last_name') ] diff --git a/templates/admin/index.html b/templates/admin/index.html index 79a4eef..9ed840a 100644 --- a/templates/admin/index.html +++ b/templates/admin/index.html @@ -46,7 +46,10 @@ {% endfor %} -

Exporter les données de stages

+ {% else %}

{% trans "You don't have permission to edit anything." %}

{% endif %} diff --git a/templates/attribution.html b/templates/attribution.html index 39bff09..72cdee4 100644 --- a/templates/attribution.html +++ b/templates/attribution.html @@ -1,23 +1,28 @@ {% extends "admin/base_site.html" %} -{% load admin_static %} +{% load i18n admin_static %} +{% load url from future %} {% block extrastyle %} {% endblock %} @@ -40,32 +45,37 @@ function update_periods(section_id) { function update_students(period_id) { $('#student_select').find('option').remove(); - $('#student_detail').html(''); + $('#student_detail').html('').removeClass("filled"); current_student = null; $('input#valid_training').hide() if (period_id == '') return; $.getJSON('/period/' + period_id + '/students/', function(data) { var sel = $('#student_select'); $.each(data, function() { - sel.append($("