participant list filtering

This commit is contained in:
Élie Bouttier 2017-08-12 22:24:55 +02:00
parent fca9a1eb1a
commit 6fc3457ddc
5 changed files with 67 additions and 43 deletions

View File

@ -125,6 +125,35 @@ class ParticipantStaffForm(ParticipantForm):
}
class ParticipantFilterForm(forms.Form):
category = forms.MultipleChoiceField(
label=_('Category'),
required=False,
widget=forms.CheckboxSelectMultiple,
choices=[],
)
status = forms.MultipleChoiceField(
label=_('Status'),
required=False,
widget=forms.CheckboxSelectMultiple,
choices=STATUS_CHOICES,
)
track = forms.MultipleChoiceField(
label=_('Track'),
required=False,
widget=forms.CheckboxSelectMultiple,
choices=[],
)
def __init__(self, *args, **kwargs):
site = kwargs.pop('site')
super().__init__(*args, **kwargs)
categories = TalkCategory.objects.filter(site=site)
self.fields['category'].choices = categories.values_list('pk', 'name')
tracks = Track.objects.filter(site=site)
self.fields['track'].choices = [('none', _('Not assigned'))] + list(tracks.values_list('slug', 'name'))
class UsersWidget(ModelSelect2MultipleWidget):
model = User
search_fields = [ '%s__icontains' % field for field in UserAdmin.search_fields ]

View File

@ -4,7 +4,7 @@ from django.core.urlresolvers import reverse
from django.core.validators import MaxValueValidator, MinValueValidator
from django.core.exceptions import ValidationError
from django.db import models
from django.db.models import Q, Sum, Avg, Case, When
from django.db.models import Q, Count, Avg, Case, When
from django.db.models.functions import Coalesce
from django.utils import timezone
from django.utils.translation import ugettext, ugettext_lazy as _
@ -69,9 +69,9 @@ class ParticipantManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
qs = qs.annotate(
accepted_talk_count=Sum(Case(When(talk__accepted=True, then=1), default=0, output_field=models.IntegerField())),
pending_talk_count=Sum(Case(When(talk__accepted=None, then=1), default=0, output_field=models.IntegerField())),
refused_talk_count=Sum(Case(When(talk__accepted=False, then=1), default=0, output_field=models.IntegerField())),
accepted_talk_count=Count(Case(When(talk__accepted=True, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
pending_talk_count=Count(Case(When(talk__accepted=None, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
refused_talk_count=Count(Case(When(talk__accepted=False, then='talk__pk'), output_field=models.IntegerField()), distinct=True),
)
return qs

View File

@ -7,30 +7,16 @@
<h1>{% trans "Speakers" %}</h1>
{% comment %}
<a class="btn btn-primary" role="button" data-toggle="collapse" href="#filter" aria-expanded="{{ show_filters|yesno:"true,false" }}" aria-controles="filter">{% trans "Show filtering options…" %}</a>
<br /><br />
<p><a class="btn btn-primary" role="button" data-toggle="collapse" href="#filter" aria-expanded="{{ show_filters|yesno:"true,false" }}" aria-controles="filter">{% trans "Show filtering options…" %}</a></p>
<div class="collapse{{ show_filters|yesno:" in," }}" id="filter">
<div class="well">
<form class="form-horizontal" method="get">
<div class="row">
<div class="col-md-6">
{% bootstrap_field filter_form.transport layout="horizontal" %}
{% bootstrap_field filter_form.transport_booked layout="horizontal" %}
{% bootstrap_field filter_form.sound layout="horizontal" %}
</div>
<div class="col-md-6">
{% bootstrap_field filter_form.accommodation layout="horizontal" %}
{% bootstrap_field filter_form.accommodation_booked layout="horizontal" %}
{% bootstrap_field filter_form.category layout="horizontal" %}
{% bootstrap_field filter_form.status layout="horizontal" %}
</div>
</div>
<div class="row">
<div class="col-md-6">
{% bootstrap_field filter_form.topic layout="horizontal" %}
</div>
<div class="col-md-6">
{% bootstrap_field filter_form.track layout="horizontal" %}
</div>
@ -39,7 +25,6 @@
</form>
</div>
</div>
{% endcomment %}
<table class="table table-bordered table-hover">
<caption>{% trans "Total:" %} {{ participant_list|length }} {% trans "speaker" %}{{ participant_list|length|pluralize }}
@ -51,13 +36,11 @@
{% comment %}<th class="text-center"></th>{% endcomment %}
</tr>
</thead>
{% comment %}
<tfoot>
<tr>
<td colspan="7">{% trans "Contact:" %} <a href="{{ contact_link }}">{% trans "link" %}</a></td>
</tr>
</tfoot>
{% endcomment %}
{% for participant in participant_list %}
{% if forloop.first %}
<tbody>
@ -84,16 +67,3 @@
</table>
{% endblock %}
{% comment %}
{% block js_end %}
<script type="text/javascript">
jQuery(document).ready(function($) {
var anchor = window.location.hash.replace("#", "");
if (anchor == "filter") {
$("#filter").collapse('show');
}
});
</script>
{% endblock %}
{% endcomment %}

View File

@ -7,9 +7,7 @@
<h1>{% trans "Talks" %}</h1>
<a class="btn btn-primary" role="button" data-toggle="collapse" href="#filter" aria-expanded="{{ show_filters|yesno:"true,false" }}" aria-controls="filter">{% trans "Show filtering options…" %}</a>
<br /><br />
<p><a class="btn btn-primary" role="button" data-toggle="collapse" href="#filter" aria-expanded="{{ show_filters|yesno:"true,false" }}" aria-controles="filter">{% trans "Show filtering options…" %}</a></p>
<div class="collapse{{ show_filters|yesno:" in," }}" id="filter">
<div class="well">

View File

@ -18,8 +18,9 @@ from .decorators import staff_required
from .mixins import StaffRequiredMixin, OnSiteMixin
from .utils import is_staff
from .models import Participant, Talk, TalkCategory, Vote, Track, Room
from .forms import TalkForm, TalkStaffForm, TalkFilterForm, TalkActionForm, ParticipantForm, \
ParticipantStaffForm, ConferenceForm, CreateUserForm, STATUS_VALUES, TrackForm, RoomForm
from .forms import TalkForm, TalkStaffForm, TalkFilterForm, TalkActionForm, \
ParticipantForm, ParticipantStaffForm, ParticipantFilterForm, \
ConferenceForm, CreateUserForm, STATUS_VALUES, TrackForm, RoomForm
def home(request):
@ -137,10 +138,10 @@ def staff(request):
@staff_required
def talk_list(request):
show_filters = False
talks = Talk.objects.filter(site=request.conference.site)
filter_form = TalkFilterForm(request.GET or None, site=request.conference.site)
# Filtering
show_filters = False
filter_form = TalkFilterForm(request.GET or None, site=request.conference.site)
if filter_form.is_valid():
data = filter_form.cleaned_data
if len(data['category']):
@ -290,8 +291,34 @@ def participant_list(request):
participants = Participant.objects.filter(site=request.conference.site) \
.extra(select={'lower_name': 'lower(name)'}) \
.order_by('lower_name')
# Filtering
show_filters = False
filter_form = ParticipantFilterForm(request.GET or None, site=request.conference.site)
if filter_form.is_valid():
data = filter_form.cleaned_data
talks = Talk.objects.filter(site=request.conference.site)
if len(data['category']):
show_filters = True
talks = talks.filter(reduce(lambda x, y: x | y, [Q(category__pk=pk) for pk in data['category']]))
if len(data['status']):
show_filters = True
talks = talks.filter(reduce(lambda x, y: x | y, [Q(accepted=dict(STATUS_VALUES)[status]) for status in data['status']]))
if len(data['track']):
show_filters = True
q = Q()
if 'none' in data['track']:
data['track'].remove('none')
q |= Q(track__isnull=True)
if len(data['track']):
q |= Q(track__slug__in=data['track'])
talks = talks.filter(q)
participants = participants.filter(talk__in=talks)
contact_link = 'mailto:' + ','.join([participant.email for participant in participants.all()])
return render(request, 'cfp/staff/participant_list.html', {
'filter_form': filter_form,
'participant_list': participants,
'show_filters': show_filters,
'contact_link': contact_link,
})