improve bda inscription form/view code

This commit is contained in:
Aurélien Delobelle 2017-04-21 18:22:53 +02:00
parent 2eee8f58aa
commit 0d8a613f28
2 changed files with 41 additions and 45 deletions

View file

@ -1,14 +1,42 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django import forms from django import forms
from django.forms.models import BaseInlineFormSet
from django.utils import timezone from django.utils import timezone
from bda.models import Attribution, Spectacle from bda.models import Attribution, Spectacle
class InscriptionInlineFormSet(BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# self.instance is a Participant object
tirage = self.instance.tirage
# set once for all "spectacle" field choices
# - restrict choices to the spectacles of this tirage
# - force_choices avoid many db requests
spectacles = tirage.spectacle_set.select_related('location')
choices = [(sp.pk, str(sp)) for sp in spectacles]
self.force_choices('spectacle', choices)
def force_choices(self, name, choices):
"""Set choices of a field.
As ModelChoiceIterator (default use to get choices of a
ModelChoiceField), it appends an empty selection if requested.
"""
for form in self.forms:
field = form.fields[name]
if field.empty_label is not None:
field.choices = [('', field.empty_label)] + choices
else:
field.choices = choices
class TokenForm(forms.Form): class TokenForm(forms.Form):
token = forms.CharField(widget=forms.widgets.Textarea()) token = forms.CharField(widget=forms.widgets.Textarea())

View file

@ -32,6 +32,7 @@ from bda.models import (
from bda.algorithm import Algorithm from bda.algorithm import Algorithm
from bda.forms import ( from bda.forms import (
TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm, TokenForm, ResellForm, AnnulForm, InscriptionReventeForm, SoldForm,
InscriptionInlineFormSet,
) )
@ -157,60 +158,27 @@ def inscription(request, tirage_id):
messages.error(request, "Le tirage n'est pas encore ouvert : " messages.error(request, "Le tirage n'est pas encore ouvert : "
"ouverture le {:s}".format(opening)) "ouverture le {:s}".format(opening))
return render(request, 'bda/resume-inscription-tirage.html', {}) return render(request, 'bda/resume-inscription-tirage.html', {})
if timezone.now() > tirage.fermeture:
# Le tirage est fermé.
participant, _ = ( participant, _ = (
Participant.objects Participant.objects.select_related('tirage')
.get_or_create(user=request.user, tirage=tirage) .get_or_create(user=request.user, tirage=tirage)
) )
if timezone.now() > tirage.fermeture:
# Le tirage est fermé.
choices = participant.choixspectacle_set.order_by("priority") choices = participant.choixspectacle_set.order_by("priority")
messages.error(request, messages.error(request,
" C'est fini : tirage au sort dans la journée !") " C'est fini : tirage au sort dans la journée !")
return render(request, "bda/resume-inscription-tirage.html", return render(request, "bda/resume-inscription-tirage.html",
{"choices": choices}) {"choices": choices})
def force_for(f, to_choices=None, **kwargs):
"""Overrides choices for ModelChoiceField.
Args:
f (models.Field): To render as forms.Field
to_choices (dict): If a key `f.name` exists, f._choices is set to
its value.
"""
formfield = f.formfield(**kwargs)
if to_choices:
if f.name in to_choices:
choices = [('', '---------')] + to_choices[f.name]
formfield._choices = choices
return formfield
# Restrict spectacles choices to spectacles for this tirage.
spectacles = (
tirage.spectacle_set
.select_related('location')
)
spectacles_field_choices = [(sp.pk, str(sp)) for sp in spectacles]
# Allow for spectacle choices to be set once for all.
# Form display use 1 request instead of (#forms of formset * #spectacles).
# FIXME: Validation still generates too much requests...
formfield_callback = partial(
force_for,
to_choices={
'spectacle': spectacles_field_choices,
},
)
BdaFormSet = inlineformset_factory( BdaFormSet = inlineformset_factory(
Participant, Participant,
ChoixSpectacle, ChoixSpectacle,
fields=("spectacle", "double_choice", "priority"), fields=("spectacle", "double_choice", "priority"),
formfield_callback=formfield_callback, formset=InscriptionInlineFormSet,
)
participant, _ = (
Participant.objects
.get_or_create(user=request.user, tirage=tirage)
) )
success = False success = False
stateerror = False stateerror = False
if request.method == "POST": if request.method == "POST":