def voting(request): conf, talks, voting_allowed = get_data_for_context(request) if not settings.VOTING_OPENED(conf, request.user): if settings.VOTING_CLOSED: return redirect(settings.VOTING_CLOSED) else: raise http.Http404() if request.method == 'POST': if not voting_allowed: return http.HttpResponseBadRequest('anonymous user not allowed') data = dict((x.id, x) for x in talks) for k, v in filter(lambda x: x[0].startswith('vote-'), request.POST.items()): try: talk = data[int(k[5:])] except KeyError: return http.HttpResponseBadRequest('invalid talk') except ValueError: return http.HttpResponseBadRequest('id malformed') if not v: models.VotoTalk.objects.filter(user=request.user, talk=talk).delete() else: try: vote = Decimal(v) except ValueError: return http.HttpResponseBadRequest('vote malformed') try: o = models.VotoTalk.objects.get(user=request.user, talk=talk) except models.VotoTalk.DoesNotExist: o = models.VotoTalk(user=request.user, talk=talk) if not vote: if o.id: o.delete() else: o.vote = vote o.save() if request.is_ajax(): return http.HttpResponse('') else: return HttpResponseRedirectSeeOther( reverse('conference-voting') + '?' + request.GET.urlencode()) else: from conference.forms import TagField, ReadonlyTagWidget, PseudoRadioRenderer class OptionForm(forms.Form): abstracts = forms.ChoiceField( choices=( ('not-voted', 'Not yet voted'), ('all', 'All'), ), required=False, initial='not-voted', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) talk_type = forms.ChoiceField( label=u'Session type', choices=(('all', 'All'), ) + tuple(settings.TALK_TYPES_TO_BE_VOTED), required=False, initial='all', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) language = forms.ChoiceField( choices=(('all', 'All'), ) + tuple(settings.TALK_SUBMISSION_LANGUAGES), required=False, initial='all', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) order = forms.ChoiceField( choices=( ('random', 'Random order'), ('vote', 'Vote'), ('speaker', 'Speaker name'), ), required=False, initial='random', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) tags = TagField( required=False, widget=ReadonlyTagWidget(), ) # I want to associate with each talk a "unique" number to display next to the title to be able to easily find. ordinal = dict() for ix, t in enumerate( talks.order_by('created').values_list('id', flat=True)): ordinal[t] = ix user_votes = models.VotoTalk.objects.filter(user=request.user.id) # Start by sorting talks by name talks = talks.order_by('speakers__user__first_name', 'speakers__user__last_name') if request.GET: form = OptionForm(data=request.GET) form.is_valid() options = form.cleaned_data else: form = OptionForm() options = { 'abstracts': 'not-voted', 'talk_type': 'all', 'language': 'all', 'tags': '', 'order': 'random', } # if options['abstracts'] == 'not-voted': # talks = talks.exclude(id__in=user_votes.values('talk_id')) if options['talk_type'] in ( tchar for (tchar, tdef) in settings.TALK_TYPES_TO_BE_VOTED): talks = talks.filter(type__startswith=options['talk_type']) if options['language'] in ( lcode for (lcode, ldef) in settings.TALK_SUBMISSION_LANGUAGES): talks = talks.filter(language=options['language']) if options['tags']: # if options['tags'] ends us a tag not associated with any talk I results # in a query that results from scratch; to avoid this limit the usable tag # as a filter to those associated with talk. allowed = set() ctt = ContentType.objects.get_for_model(models.Talk) for t, usage in dataaccess.tags().items(): for cid, oid in usage: if cid == ctt.id: allowed.add(t.name) break tags = set(options['tags']) & allowed if tags: talks = talks.filter(id__in=models.ConferenceTaggedItem.objects\ .filter( content_type__app_label='conference', content_type__model='talk', tag__name__in=tags)\ .values('object_id') ) talk_order = options['order'] votes = dict((x.talk_id, x) for x in user_votes) # As talks are sorted by a model connected via a m2m can I have repeated the talk, and # distinct does not apply in these case. # # It can only filtered in python, at this point I take this opportunity to engage # votes user using a single loop. dups = set() def filter_vote(t): if t['id'] in dups: return False dups.add(t['id']) t['user_vote'] = votes.get(t['id']) t['ordinal'] = ordinal[t['id']] return True talks = filter(filter_vote, talks.values('id')) # Fix talk order, if necessary if talk_order == 'vote': def key(x): if x['user_vote']: return x['user_vote'].vote else: return Decimal('-99.99') talks = reversed(sorted(reversed(talks), key=key)) elif talk_order == 'random': random.shuffle(talks) elif talk_order == 'speaker': # Already sorted pass ctx = { 'voting_allowed': voting_allowed, 'talks': list(talks), 'form': form, } if request.is_ajax(): tpl = 'conference/ajax/voting.html' else: tpl = 'conference/voting.html' return render(request, tpl, ctx)
def filter_talks_in_context(request, talks, voting_allowed): # Want to associate each talk with a "unique" number, easily find. ordinal = dict() for ix, t in enumerate( talks.order_by('created').values_list('id', flat=True)): ordinal[t] = ix user_votes = models.VotoTalk.objects.filter(user=request.user.id) talks = talks.order_by('speakers__user__first_name', 'speakers__user__last_name') if request.GET: form = OptionForm(data=request.GET) form.is_valid() options = form.cleaned_data else: form = OptionForm() options = { 'abstracts': 'not-voted', 'talk_type': '', 'language': '', 'tags': '', 'order': 'vote', } if options['abstracts'] != 'all': talks = talks.exclude(id__in=user_votes.values('talk_id')) if options['talk_type'] in ('s', 't', 'p'): talks = talks.filter(type=options['talk_type']) if options['language'] in ('en', 'it'): talks = talks.filter(language=options['language']) if options['tags']: # if options['tags'] ends us a tag not associated with any talk. # I have a query that results in zero results; to avoid this limit the usable # tag as a filter to those associated with talk. allowed = set() ctt = ContentType.objects.get_for_model(models.Talk) for t, usage in dataaccess.tags().items(): for cid, oid in usage: if cid == ctt.id: allowed.add(t.name) break tags = set(options['tags']) & allowed if tags: talks = talks.filter(id__in=models.ConferenceTaggedItem.objects \ .filter( content_type__app_label='conference', content_type__model='talk', tag__name__in=tags) \ .values('object_id') ) talk_order = options['order'] votes = dict((x.talk_id, x) for x in user_votes) # As talks are sorted by a linked model through a m2m can I have repeated # the talk and distinct does not apply in these cases. # # I can only filter in Python, at this point I take this opportunity to # engage votes user using a single loop. dups = set() def filter_vote(t): if t['id'] in dups: return False dups.add(t['id']) t['user_vote'] = votes.get(t['id']) t['ordinal'] = ordinal[t['id']] return True talks = filter(filter_vote, talks.values('id')) if talk_order != 'speaker': def key(x): if x['user_vote']: return x['user_vote'].vote else: return Decimal('-99.99') talks = reversed(sorted(reversed(talks), key=key)) ctx = { 'voting_allowed': voting_allowed, 'talks': list(talks), 'form': form, } return ctx
def voting(request): conf, talks, voting_allowed = get_data_for_context(request) if not settings.VOTING_OPENED(conf, request.user): if settings.VOTING_CLOSED: return redirect(settings.VOTING_CLOSED) else: raise http.Http404() if request.method == 'POST': if not voting_allowed: return http.HttpResponseBadRequest('anonymous user not allowed') data = dict((x.id, x) for x in talks) for k, v in filter(lambda x: x[0].startswith('vote-'), request.POST.items()): try: talk = data[int(k[5:])] except KeyError: return http.HttpResponseBadRequest('invalid talk') except ValueError: return http.HttpResponseBadRequest('id malformed') if not v: models.VotoTalk.objects.filter(user=request.user, talk=talk).delete() else: try: vote = Decimal(v) except ValueError: return http.HttpResponseBadRequest('vote malformed') try: o = models.VotoTalk.objects.get(user=request.user, talk=talk) except models.VotoTalk.DoesNotExist: o = models.VotoTalk(user=request.user, talk=talk) if not vote: if o.id: o.delete() else: o.vote = vote o.save() if request.is_ajax(): return http.HttpResponse('') else: return HttpResponseRedirectSeeOther( reverse('conference-voting') + '?' + request.GET.urlencode()) else: from conference.forms import TagField, ReadonlyTagWidget, PseudoRadioRenderer class OptionForm(forms.Form): abstracts = forms.ChoiceField( choices=( ('not-voted', 'To be voted'), ('all', 'All'), ), required=False, initial='not-voted', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) talk_type = forms.ChoiceField( choices=settings.TALK_TYPES_TO_BE_VOTED, required=False, initial='all', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) language = forms.ChoiceField( choices=( ('all', 'All'), ('en', 'English'), ('it', 'Italian'), ), required=False, initial='all', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) order = forms.ChoiceField( choices=( ('vote', 'Vote'), ('speaker', 'Speaker name'), ), required=False, initial='vote', widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) tags = TagField( required=False, widget=ReadonlyTagWidget(), ) # voglio poter associare ad ogni talk un numero "univoco" da mostrare # accanto al titolo per poterlo individuare facilmente. ordinal = dict() for ix, t in enumerate( talks.order_by('created').values_list('id', flat=True)): ordinal[t] = ix user_votes = models.VotoTalk.objects.filter(user=request.user.id) talks = talks.order_by('speakers__user__first_name', 'speakers__user__last_name') if request.GET: form = OptionForm(data=request.GET) form.is_valid() options = form.cleaned_data else: form = OptionForm() options = { 'abstracts': 'not-voted', 'talk_type': '', 'language': '', 'tags': '', 'order': 'vote', } if options['abstracts'] != 'all': talks = talks.exclude(id__in=user_votes.values('talk_id')) if options['talk_type'] in ('s', 't', 'p'): talks = talks.filter(type=options['talk_type']) if options['language'] in ('en', 'it'): talks = talks.filter(language=options['language']) if options['tags']: # se in options['tags'] ci finisce un tag non associato ad alcun # talk ho come risultato una query che da zero risultati; per # evitare questo limito i tag usabili come filtro a quelli # associati ai talk. allowed = set() ctt = ContentType.objects.get_for_model(models.Talk) for t, usage in dataaccess.tags().items(): for cid, oid in usage: if cid == ctt.id: allowed.add(t.name) break tags = set(options['tags']) & allowed if tags: talks = talks.filter(id__in=models.ConferenceTaggedItem.objects\ .filter( content_type__app_label='conference', content_type__model='talk', tag__name__in=tags)\ .values('object_id') ) talk_order = options['order'] votes = dict((x.talk_id, x) for x in user_votes) # Poichè talks è ordinato per un modello collegato tramite una # ManyToMany posso avere dei talk ripetuti, e il distinct non si # applica in questi casi. # # Non mi rimane che filtrare in python, a questo punto ne approfitto # per agganciare i voti dell'utente utilizzando un unico loop. dups = set() def filter_vote(t): if t['id'] in dups: return False dups.add(t['id']) t['user_vote'] = votes.get(t['id']) t['ordinal'] = ordinal[t['id']] return True talks = filter(filter_vote, talks.values('id')) if talk_order != 'speaker': def key(x): if x['user_vote']: return x['user_vote'].vote else: return Decimal('-99.99') talks = reversed(sorted(reversed(talks), key=key)) ctx = { 'voting_allowed': voting_allowed, 'talks': list(talks), 'form': form, } if request.is_ajax(): tpl = 'conference/ajax/voting.html' else: tpl = 'conference/voting.html' return render(request, tpl, ctx)
def filter_talks_in_context(request, talks, voting_allowed): # voglio poter associare ad ogni talk un numero "univoco" da mostrare # accanto al titolo per poterlo individuare facilmente. ordinal = dict() for ix, t in enumerate( talks.order_by('created').values_list('id', flat=True)): ordinal[t] = ix user_votes = models.VotoTalk.objects.filter(user=request.user.id) talks = talks.order_by('speakers__user__first_name', 'speakers__user__last_name') if request.GET: form = OptionForm(data=request.GET) form.is_valid() options = form.cleaned_data else: form = OptionForm() options = { 'abstracts': 'not-voted', 'talk_type': '', 'language': '', 'tags': '', 'order': 'vote', } if options['abstracts'] != 'all': talks = talks.exclude(id__in=user_votes.values('talk_id')) if options['talk_type'] in ('s', 't', 'p'): talks = talks.filter(type=options['talk_type']) if options['language'] in ('en', 'it'): talks = talks.filter(language=options['language']) if options['tags']: # se in options['tags'] ci finisce un tag non associato ad alcun # talk ho come risultato una query che da zero risultati; per # evitare questo limito i tag usabili come filtro a quelli # associati ai talk. allowed = set() ctt = ContentType.objects.get_for_model(models.Talk) for t, usage in dataaccess.tags().items(): for cid, oid in usage: if cid == ctt.id: allowed.add(t.name) break tags = set(options['tags']) & allowed if tags: talks = talks.filter(id__in=models.ConferenceTaggedItem.objects \ .filter( content_type__app_label='conference', content_type__model='talk', tag__name__in=tags) \ .values('object_id') ) talk_order = options['order'] votes = dict((x.talk_id, x) for x in user_votes) # Poichè talks è ordinato per un modello collegato tramite una # ManyToMany posso avere dei talk ripetuti, e il distinct non si # applica in questi casi. # # Non mi rimane che filtrare in python, a questo punto ne approfitto # per agganciare i voti dell'utente utilizzando un unico loop. dups = set() def filter_vote(t): if t['id'] in dups: return False dups.add(t['id']) t['user_vote'] = votes.get(t['id']) t['ordinal'] = ordinal[t['id']] return True talks = filter(filter_vote, talks.values('id')) if talk_order != 'speaker': def key(x): if x['user_vote']: return x['user_vote'].vote else: return Decimal('-99.99') talks = reversed(sorted(reversed(talks), key=key)) ctx = { 'voting_allowed': voting_allowed, 'talks': list(talks), 'form': form, } return ctx
def voting(request): conf, talks, voting_allowed = get_data_for_context(request) if not settings.VOTING_OPENED(conf, request.user): if settings.VOTING_CLOSED: return redirect(settings.VOTING_CLOSED) else: raise http.Http404() if request.method == "POST": if not voting_allowed: return http.HttpResponseBadRequest("anonymous user not allowed") data = dict((x.id, x) for x in talks) for k, v in filter(lambda x: x[0].startswith("vote-"), request.POST.items()): try: talk = data[int(k[5:])] except KeyError: return http.HttpResponseBadRequest("invalid talk") except ValueError: return http.HttpResponseBadRequest("id malformed") if not v: models.VotoTalk.objects.filter(user=request.user, talk=talk).delete() else: try: vote = Decimal(v) except ValueError: return http.HttpResponseBadRequest("vote malformed") try: o = models.VotoTalk.objects.get(user=request.user, talk=talk) except models.VotoTalk.DoesNotExist: o = models.VotoTalk(user=request.user, talk=talk) if not vote: if o.id: o.delete() else: o.vote = vote o.save() if request.is_ajax(): return http.HttpResponse("") else: return HttpResponseRedirectSeeOther(reverse("conference-voting") + "?" + request.GET.urlencode()) else: from conference.forms import TagField, ReadonlyTagWidget, PseudoRadioRenderer class OptionForm(forms.Form): abstracts = forms.ChoiceField( choices=(("not-voted", "To be voted"), ("all", "All")), required=False, initial="not-voted", widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) talk_type = forms.ChoiceField( choices=settings.TALK_TYPES_TO_BE_VOTED, required=False, initial="all", widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) language = forms.ChoiceField( choices=(("all", "All"), ("en", "English"), ("it", "Italian")), required=False, initial="all", widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) order = forms.ChoiceField( choices=(("vote", "Vote"), ("speaker", "Speaker name")), required=False, initial="vote", widget=forms.RadioSelect(renderer=PseudoRadioRenderer), ) tags = TagField(required=False, widget=ReadonlyTagWidget()) # voglio poter associare ad ogni talk un numero "univoco" da mostrare # accanto al titolo per poterlo individuare facilmente. ordinal = dict() for ix, t in enumerate(talks.order_by("created").values_list("id", flat=True)): ordinal[t] = ix user_votes = models.VotoTalk.objects.filter(user=request.user.id) talks = talks.order_by("speakers__user__first_name", "speakers__user__last_name") if request.GET: form = OptionForm(data=request.GET) form.is_valid() options = form.cleaned_data else: form = OptionForm() options = {"abstracts": "not-voted", "talk_type": "", "language": "", "tags": "", "order": "vote"} if options["abstracts"] != "all": talks = talks.exclude(id__in=user_votes.values("talk_id")) if options["talk_type"] in ("s", "t", "p"): talks = talks.filter(type=options["talk_type"]) if options["language"] in ("en", "it"): talks = talks.filter(language=options["language"]) if options["tags"]: # se in options['tags'] ci finisce un tag non associato ad alcun # talk ho come risultato una query che da zero risultati; per # evitare questo limito i tag usabili come filtro a quelli # associati ai talk. allowed = set() ctt = ContentType.objects.get_for_model(models.Talk) for t, usage in dataaccess.tags().items(): for cid, oid in usage: if cid == ctt.id: allowed.add(t.name) break tags = set(options["tags"]) & allowed if tags: talks = talks.filter( id__in=models.ConferenceTaggedItem.objects.filter( content_type__app_label="conference", content_type__model="talk", tag__name__in=tags ).values("object_id") ) talk_order = options["order"] votes = dict((x.talk_id, x) for x in user_votes) # Poichè talks è ordinato per un modello collegato tramite una # ManyToMany posso avere dei talk ripetuti, e il distinct non si # applica in questi casi. # # Non mi rimane che filtrare in python, a questo punto ne approfitto # per agganciare i voti dell'utente utilizzando un unico loop. dups = set() def filter_vote(t): if t["id"] in dups: return False dups.add(t["id"]) t["user_vote"] = votes.get(t["id"]) t["ordinal"] = ordinal[t["id"]] return True talks = filter(filter_vote, talks.values("id")) if talk_order != "speaker": def key(x): if x["user_vote"]: return x["user_vote"].vote else: return Decimal("-99.99") talks = reversed(sorted(reversed(talks), key=key)) ctx = {"voting_allowed": voting_allowed, "talks": list(talks), "form": form} if request.is_ajax(): tpl = "conference/ajax/voting.html" else: tpl = "conference/voting.html" return render(request, tpl, ctx)
def filter_talks_in_context(request, talks, voting_allowed): # voglio poter associare ad ogni talk un numero "univoco" da mostrare # accanto al titolo per poterlo individuare facilmente. ordinal = dict() for ix, t in enumerate(talks.order_by("created").values_list("id", flat=True)): ordinal[t] = ix user_votes = models.VotoTalk.objects.filter(user=request.user.id) talks = talks.order_by("speakers__user__first_name", "speakers__user__last_name") if request.GET: form = OptionForm(data=request.GET) form.is_valid() options = form.cleaned_data else: form = OptionForm() options = {"abstracts": "not-voted", "talk_type": "", "language": "", "tags": "", "order": "vote"} if options["abstracts"] != "all": talks = talks.exclude(id__in=user_votes.values("talk_id")) if options["talk_type"] in ("s", "t", "p"): talks = talks.filter(type=options["talk_type"]) if options["language"] in ("en", "it"): talks = talks.filter(language=options["language"]) if options["tags"]: # se in options['tags'] ci finisce un tag non associato ad alcun # talk ho come risultato una query che da zero risultati; per # evitare questo limito i tag usabili come filtro a quelli # associati ai talk. allowed = set() ctt = ContentType.objects.get_for_model(models.Talk) for t, usage in dataaccess.tags().items(): for cid, oid in usage: if cid == ctt.id: allowed.add(t.name) break tags = set(options["tags"]) & allowed if tags: talks = talks.filter( id__in=models.ConferenceTaggedItem.objects.filter( content_type__app_label="conference", content_type__model="talk", tag__name__in=tags ).values("object_id") ) talk_order = options["order"] votes = dict((x.talk_id, x) for x in user_votes) # Poichè talks è ordinato per un modello collegato tramite una # ManyToMany posso avere dei talk ripetuti, e il distinct non si # applica in questi casi. # # Non mi rimane che filtrare in python, a questo punto ne approfitto # per agganciare i voti dell'utente utilizzando un unico loop. dups = set() def filter_vote(t): if t["id"] in dups: return False dups.add(t["id"]) t["user_vote"] = votes.get(t["id"]) t["ordinal"] = ordinal[t["id"]] return True talks = filter(filter_vote, talks.values("id")) if talk_order != "speaker": def key(x): if x["user_vote"]: return x["user_vote"].vote else: return Decimal("-99.99") talks = reversed(sorted(reversed(talks), key=key)) ctx = {"voting_allowed": voting_allowed, "talks": list(talks), "form": form} return ctx