Add new widget (not tested) and new bdd scheme for elections

This commit is contained in:
Antoine Bartuccio 2016-12-20 16:00:14 +01:00
parent 7956067686
commit d72d8366cf
7 changed files with 191 additions and 7 deletions

View File

@ -370,8 +370,8 @@ Cette page vise à documenter la syntaxe *Markdown* utilisée sur le site.
el.save()
el.view_groups.add(public_group)
el.edit_groups.add(ae_board_gorup)
el.candidature_group.add(subscriber_group)
el.vote_group.add(subscriber_group)
el.candidature_groups.add(subscriber_group)
el.vote_groups.add(subscriber_group)
el.save()
liste = ElectionList(title="Candidature Libre", election=el)
liste.save()

94
core/widgets.py Normal file
View File

@ -0,0 +1,94 @@
from django import forms
from django.utils.safestring import mark_safe
class ChoiceWithOtherRenderer(forms.RadioSelect.renderer):
"""RadioFieldRenderer that renders its last choice with a placeholder."""
def __init__(self, *args, **kwargs):
super(ChoiceWithOtherRenderer, self).__init__(*args, **kwargs)
self.choices, self.other = self.choices[:-1], self.choices[-1]
def __iter__(self):
for input in super(ChoiceWithOtherRenderer, self).__iter__():
yield input
id = '%s_%s' % (self.attrs['id'], self.other[0]) if 'id' in self.attrs else ''
label_for = ' for="%s"' % id if id else ''
checked = '' if not self.other[0] == self.value else 'checked="true" '
yield '<label%s><input type="radio" id="%s" value="%s" name="%s" %s/> %s</label> %%s' % (
label_for, id, self.other[0], self.name, checked, self.other[1])
class ChoiceWithOtherWidget(forms.MultiWidget):
"""MultiWidget for use with ChoiceWithOtherField."""
def __init__(self, choices):
widgets = [
forms.RadioSelect(choices=choices, renderer=ChoiceWithOtherRenderer),
forms.TextInput
]
super(ChoiceWithOtherWidget, self).__init__(widgets)
def decompress(self, value):
if not value:
return [None, None]
return value
def format_output(self, rendered_widgets):
"""Format the output by substituting the "other" choice into the first widget."""
return rendered_widgets[0] % rendered_widgets[1]
class ChoiceWithOtherField(forms.MultiValueField):
"""
ChoiceField with an option for a user-submitted "other" value.
The last item in the choices array passed to __init__ is expected to be a choice for "other". This field's
cleaned data is a tuple consisting of the choice the user made, and the "other" field typed in if the choice
made was the last one.
>>> class AgeForm(forms.Form):
... age = ChoiceWithOtherField(choices=[
... (0, '15-29'),
... (1, '30-44'),
... (2, '45-60'),
... (3, 'Other, please specify:')
... ])
...
>>> # rendered as a RadioSelect choice field whose last choice has a text input
... print AgeForm()['age']
<ul>
<li><label for="id_age_0_0"><input type="radio" id="id_age_0_0" value="0" name="age_0" /> 15-29</label></li>
<li><label for="id_age_0_1"><input type="radio" id="id_age_0_1" value="1" name="age_0" /> 30-44</label></li>
<li><label for="id_age_0_2"><input type="radio" id="id_age_0_2" value="2" name="age_0" /> 45-60</label></li>
<li><label for="id_age_0_3"><input type="radio" id="id_age_0_3" value="3" name="age_0" /> Other, please \
specify:</label> <input type="text" name="age_1" id="id_age_1" /></li>
</ul>
>>> form = AgeForm({'age_0': 2})
>>> form.is_valid()
True
>>> form.cleaned_data
{'age': (u'2', u'')}
>>> form = AgeForm({'age_0': 3, 'age_1': 'I am 10 years old'})
>>> form.is_valid()
True
>>> form.cleaned_data
{'age': (u'3', u'I am 10 years old')}
>>> form = AgeForm({'age_0': 1, 'age_1': 'This is bogus text which is ignored since I didn\\'t pick "other"'})
>>> form.is_valid()
True
>>> form.cleaned_data
{'age': (u'1', u'')}
"""
def __init__(self, *args, **kwargs):
fields = [
forms.ChoiceField(widget=forms.RadioSelect(renderer=ChoiceWithOtherRenderer), *args, **kwargs),
forms.CharField(required=False)
]
widget = ChoiceWithOtherWidget(choices=kwargs['choices'])
kwargs.pop('choices')
self._was_required = kwargs.pop('required', True)
kwargs['required'] = False
super(ChoiceWithOtherField, self).__init__(widget=widget, fields=fields, *args, **kwargs)
def compress(self, value):
if self._was_required and not value or value[0] in (None, ''):
raise forms.ValidationError(self.error_messages['required'])
if not value:
return [None, u'']
return (value[0], value[1] if value[0] == self.fields[0].choices[-1][0] else u'')

View File

@ -0,0 +1,43 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0016_auto_20161212_1922'),
('election', '0003_auto_20161219_1832'),
]
operations = [
migrations.RemoveField(
model_name='election',
name='candidature_group',
),
migrations.RemoveField(
model_name='election',
name='vote_group',
),
migrations.AddField(
model_name='election',
name='candidature_groups',
field=models.ManyToManyField(to='core.Group', verbose_name='candidature group', related_name='candidate_elections', blank=True),
),
migrations.AddField(
model_name='election',
name='vote_groups',
field=models.ManyToManyField(to='core.Group', verbose_name='vote group', related_name='votable_elections', blank=True),
),
migrations.AlterField(
model_name='election',
name='edit_groups',
field=models.ManyToManyField(to='core.Group', verbose_name='edit group', related_name='editable_elections', blank=True),
),
migrations.AlterField(
model_name='election',
name='view_groups',
field=models.ManyToManyField(to='core.Group', verbose_name='view group', related_name='viewable_elections', blank=True),
),
]

View File

@ -18,10 +18,10 @@ class Election(models.Model):
start_date = models.DateTimeField(_('start date'), blank=False)
end_date = models.DateTimeField(_('end date'), blank=False)
edit_groups = models.ManyToManyField(Group, related_name="editable_election", verbose_name=_("edit group"), blank=True)
view_groups = models.ManyToManyField(Group, related_name="viewable_election", verbose_name=_("view group"), blank=True)
vote_group = models.ManyToManyField(Group, related_name="votable_election", verbose_name=_("vote group"), blank=True)
candidature_group = models.ManyToManyField(Group, related_name="candidate_election", verbose_name=_("candidature group"), blank=True)
edit_groups = models.ManyToManyField(Group, related_name="editable_elections", verbose_name=_("edit group"), blank=True)
view_groups = models.ManyToManyField(Group, related_name="viewable_elections", verbose_name=_("view group"), blank=True)
vote_groups = models.ManyToManyField(Group, related_name="votable_elections", verbose_name=_("vote group"), blank=True)
candidature_groups = models.ManyToManyField(Group, related_name="candidate_elections", verbose_name=_("candidature group"), blank=True)
def __str__(self):
return self.title

View File

@ -11,14 +11,21 @@
<h1>{{object.title}}</h1>
<p>{{object.description}}</p>
<p>{% trans %}End :{% endtrans %} {{object.end_date}}</p>
{% if object.election_list.exists() %}
<table>
<tr>
{% set nb_list = object.election_list.all().count() + 1 -%}
{% for liste in object.election_list.all() %}
<td>{{liste.title}}</td>
{% if object.is_candidature_active -%}
{% set nb_list = nb_list -%}
{% else -%}
{% set nb_list = nb_list + 1 -%}
{% endif -%}
{% endfor %}
{% if not object.is_candidature_active -%}
<td>{% trans %}Blank vote{% endtrans %}</td>
{% endif %}
</tr>
{% for role in object.role.all() %}
<tr><td colspan={{nb_list}}>{{role.title}}</td></tr>
@ -40,8 +47,14 @@
</ul>
</td>
{% endfor %}
{% if not object.is_candidature_active -%}
<td></td>
{% endif %}
</tr>
{% endfor %}
</table>
{% endif %}
{% if object.is_candidature_active -%}
candidature
{% endif -%}
{% endblock %}

View File

@ -4,5 +4,6 @@ from election.views import *
urlpatterns = [
url(r'^$', ElectionsListView.as_view(), name='list'),
url(r'^create$', PageCreateView.as_view(), name='create'),
url(r'^(?P<election_id>[0-9]+)/detail$', ElectionDetailView.as_view(), name='detail'),
]

View File

@ -3,12 +3,25 @@ from django.views.generic import ListView, DetailView, RedirectView
from django.views.generic.edit import UpdateView, CreateView, DeleteView, FormView
from django.core.urlresolvers import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _
from django.forms.models import modelform_factory
from django.forms import CheckboxSelectMultiple
from django.utils import timezone
from django.conf import settings
from django import forms
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin, CanCreateMixin
from core.views.forms import SelectDateTime
from core.widgets import ChoiceWithOtherField
from election.models import Election, Role, Candidature
from ajax_select.fields import AutoCompleteSelectField
# Forms
class CandidateForm(forms.Form):
user = AutoCompleteSelectField('users', label=_('Refound this account'), help_text=None, required=True)
# Display elections
@ -34,4 +47,24 @@ class ElectionDetailView(CanViewMixin, DetailView):
template_name = 'election/election_detail.jinja'
pk_url_kwarg = "election_id"
# Forms
class PageCreateView(CanCreateMixin, CreateView):
model = Election
form_class = modelform_factory(Election,
fields=['title', 'description', 'start_candidature', 'end_candidature', 'start_date', 'end_date',
'edit_groups', 'view_groups', 'vote_groups', 'candidature_groups'],
widgets={
'edit_groups': CheckboxSelectMultiple,
'view_groups': CheckboxSelectMultiple,
'edit_groups': CheckboxSelectMultiple,
'vote_groups': CheckboxSelectMultiple,
'candidature_groups': CheckboxSelectMultiple,
'start_date': SelectDateTime,
'end_date': SelectDateTime,
'start_candidature': SelectDateTime,
'end_candidature': SelectDateTime,
})
template_name = 'core/page_prop.jinja'
def get_success_url(self, **kwargs):
return reverse_lazy('election:detail', kwargs={'election_id': self.object.id})