Tally votes, cache results and allow for publication/depublication
This commit is contained in:
parent
9c6eaeef58
commit
3387186f76
6 changed files with 97 additions and 9 deletions
20
elections/migrations/0004_option_nb_votes.py
Normal file
20
elections/migrations/0004_option_nb_votes.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.17 on 2020-12-19 16:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("elections", "0003_auto_20201218_1954"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="option",
|
||||
name="nb_votes",
|
||||
field=models.PositiveSmallIntegerField(
|
||||
default=0, verbose_name="nombre de votes reçus"
|
||||
),
|
||||
),
|
||||
]
|
20
elections/migrations/0005_question_max_votes.py
Normal file
20
elections/migrations/0005_question_max_votes.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.17 on 2020-12-19 17:19
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("elections", "0004_option_nb_votes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="question",
|
||||
name="max_votes",
|
||||
field=models.PositiveSmallIntegerField(
|
||||
default=0, verbose_name="nombre maximal de votes reçus"
|
||||
),
|
||||
),
|
||||
]
|
|
@ -29,6 +29,10 @@ class Question(models.Model):
|
|||
Election, related_name="questions", on_delete=models.CASCADE
|
||||
)
|
||||
text = models.TextField(_("question"), blank=False)
|
||||
# We cache the maximum number of votes for an option
|
||||
max_votes = models.PositiveSmallIntegerField(
|
||||
_("nombre maximal de votes reçus"), default=0
|
||||
)
|
||||
|
||||
|
||||
class Option(models.Model):
|
||||
|
@ -40,3 +44,5 @@ class Option(models.Model):
|
|||
User,
|
||||
related_name="votes",
|
||||
)
|
||||
# For now, we store the amount of votes received after the election is tallied
|
||||
nb_votes = models.PositiveSmallIntegerField(_("nombre de votes reçus"), default=0)
|
||||
|
|
|
@ -47,13 +47,17 @@
|
|||
{% else %}
|
||||
|
||||
{# Lien pour la publication des résultats #}
|
||||
<a class="button is-light is-outlined is-primary" href="{% url 'election.publish' election.pk %}">
|
||||
<a class="button is-outlined is-primary" href="{% url 'election.publish' election.pk %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-edit"></i>
|
||||
</span>
|
||||
|
||||
{% if not election.results_public %}
|
||||
{% trans "Publier" %}
|
||||
</a>
|
||||
{% else %}
|
||||
{% trans "Dépublier" %}
|
||||
{% endif %}
|
||||
</a>
|
||||
|
||||
{# Lien pour l'archivage #}
|
||||
<a class="button is-light is-outlined is-primary" href="{% url 'election.archive' election.pk %}">
|
||||
|
@ -116,8 +120,12 @@
|
|||
</a>
|
||||
</div>
|
||||
{% elif election.tallied %}
|
||||
<span class="tag is-primary">
|
||||
</span>
|
||||
<span class="tag {% if o.nb_votes == q.max_votes %}is-success{% else %}is-primary{% endif %}">
|
||||
<span class="icon">
|
||||
<i class="fas fa-vote-yea"></i>
|
||||
</span>
|
||||
{{ o.nb_votes }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{{ o.text }}
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,9 @@ urlpatterns = [
|
|||
path("update/<int:pk>", views.ElectionUpdateView.as_view(), name="election.update"),
|
||||
path("tally/<int:pk>", views.ElectionTallyView.as_view(), name="election.tally"),
|
||||
path(
|
||||
"publish/<int:pk>", views.ElectionPublishView.as_view(), name="election.publish"
|
||||
"publish/<int:pk>",
|
||||
views.ElectionChangePublicationView.as_view(),
|
||||
name="election.publish",
|
||||
),
|
||||
path(
|
||||
"archive/<int:pk>", views.ElectionArchiveView.as_view(), name="election.archive"
|
||||
|
|
|
@ -50,28 +50,60 @@ class ElectionUpdateView(SuccessMessageMixin, UpdateView):
|
|||
|
||||
class ElectionTallyView(SuccessMessageMixin, SingleObjectMixin, RedirectView):
|
||||
model = Election
|
||||
pattern_name = "election.admin"
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().prefetch_related("questions__options")
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
election = self.get_object()
|
||||
election.update(tallied=True)
|
||||
options, questions = [], []
|
||||
for q in election.questions.all():
|
||||
max_votes = 0
|
||||
for o in q.options.all():
|
||||
o.nb_votes = o.voters.count()
|
||||
max_votes = max(max_votes, o.nb_votes)
|
||||
options.append(o)
|
||||
|
||||
q.max_votes = max_votes
|
||||
questions.append(q)
|
||||
|
||||
Option.objects.bulk_update(options, ["nb_votes"])
|
||||
Question.objects.bulk_update(questions, ["max_votes"])
|
||||
election.tallied = True
|
||||
election.save()
|
||||
messages.success(request, _("Élection dépouillée avec succès !"))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ElectionPublishView(SuccessMessageMixin, SingleObjectMixin, RedirectView):
|
||||
class ElectionChangePublicationView(
|
||||
SuccessMessageMixin, SingleObjectMixin, RedirectView
|
||||
):
|
||||
model = Election
|
||||
pattern_name = "election.admin"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
election = self.get_object()
|
||||
election.update(tallied=True)
|
||||
election.results_public = not election.results_public
|
||||
election.save()
|
||||
messages.success(
|
||||
request,
|
||||
_("Élection publiée avec succès !")
|
||||
if election.results_public
|
||||
else _("Élection dépubliée avec succès !"),
|
||||
)
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ElectionArchiveView(SuccessMessageMixin, SingleObjectMixin, RedirectView):
|
||||
model = Election
|
||||
pattern_name = "election.admin"
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
election = self.get_object()
|
||||
election.update(tallied=True)
|
||||
election.archived = True
|
||||
election.save()
|
||||
messages.success(request, _("Élection archivée avec succès !"))
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue