diff --git a/bda/forms.py b/bda/forms.py index 3565bedf..c0417d1e 100644 --- a/bda/forms.py +++ b/bda/forms.py @@ -1,14 +1,42 @@ # -*- coding: utf-8 -*- -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - from django import forms +from django.forms.models import BaseInlineFormSet from django.utils import timezone + 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): token = forms.CharField(widget=forms.widgets.Textarea()) diff --git a/bda/views.py b/bda/views.py index 6e0e73b6..00a1b300 100644 --- a/bda/views.py +++ b/bda/views.py @@ -32,6 +32,7 @@ from bda.models import ( from bda.algorithm import Algorithm from bda.forms import ( 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 : " "ouverture le {:s}".format(opening)) return render(request, 'bda/resume-inscription-tirage.html', {}) + + participant, _ = ( + Participant.objects.select_related('tirage') + .get_or_create(user=request.user, tirage=tirage) + ) + if timezone.now() > tirage.fermeture: # Le tirage est fermé. - participant, _ = ( - Participant.objects - .get_or_create(user=request.user, tirage=tirage) - ) choices = participant.choixspectacle_set.order_by("priority") messages.error(request, " C'est fini : tirage au sort dans la journée !") return render(request, "bda/resume-inscription-tirage.html", {"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( Participant, ChoixSpectacle, fields=("spectacle", "double_choice", "priority"), - formfield_callback=formfield_callback, - ) - participant, _ = ( - Participant.objects - .get_or_create(user=request.user, tirage=tirage) + formset=InscriptionInlineFormSet, ) + success = False stateerror = False if request.method == "POST":