Mercurial > public > sg101
changeset 447:8f46ba2f1b81
For #219, rework the polls views for a better flow. Added some tests for the views.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Sat, 25 Jun 2011 23:23:20 +0000 |
parents | 72ef6e809f79 |
children | f55d7f08632f |
files | gpp/polls/tests/__init__.py gpp/polls/tests/view_tests.py gpp/polls/urls.py gpp/polls/views.py gpp/templates/polls/latest_poll_tag.html gpp/templates/polls/poll.html gpp/templates/polls/poll_detail.html gpp/templates/polls/poll_results.html gpp/templates/polls/poll_vote.html |
diffstat | 9 files changed, 262 insertions(+), 114 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/polls/tests/__init__.py Sat Jun 25 23:23:20 2011 +0000 @@ -0,0 +1,1 @@ +from view_tests import *
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/polls/tests/view_tests.py Sat Jun 25 23:23:20 2011 +0000 @@ -0,0 +1,178 @@ +""" +Tests for the views in the polls application. + +""" +import datetime + +from django.contrib.auth.models import User +from django.test import TestCase +from django.core.urlresolvers import reverse +from polls.models import Poll, Choice + + +class PollHomeTest(TestCase): + + def setUp(self): + now = datetime.datetime.now() + Poll.objects.all().delete() + + past = now - datetime.timedelta(7) + future = now + datetime.timedelta(7) + + Poll.objects.create(start_date=past, + end_date=past, + is_enabled=True, + question='Old Poll') + + active = Poll.objects.create(start_date=past, + end_date=future, + is_enabled=True, + question='Active Poll') + + Poll.objects.create(start_date=future, + end_date=future, + is_enabled=True, + question='Future Poll') + + Poll.objects.create(start_date=past, + end_date=future, + is_enabled=False, + question='Disabled Poll') + + choice1 = Choice.objects.create(poll=active, choice="Yes") + choice2 = Choice.objects.create(poll=active, choice="Yes") + + self.username = 'test_user' + self.pw = 'password' + self.user = User.objects.create_user(self.username, '', self.pw) + self.user.save() + self.assertTrue(self.client.login(username=self.username, + password=self.pw)) + + def tearDown(self): + self.client.logout() + + def testHome(self): + response = self.client.get(reverse('polls-main')) + + old = response.context['old_polls'] + self.assertEqual(len(old), 1) + if old: + self.assertEqual(old[0].question, 'Old Poll') + + current = response.context['current_polls'] + self.assertEqual(len(current), 1) + if current: + self.assertEqual(current[0].question, 'Active Poll') + + self.assertNotContains(response, 'Future Poll') + self.assertNotContains(response, 'Disabled Poll') + + def testFuture(self): + poll = Poll.objects.get(question='Future Poll') + response = self.client.get(reverse('polls-detail', kwargs={'poll_id': + poll.id})) + self.assertEqual(response.status_code, 404) + + def testDisabled(self): + poll = Poll.objects.get(question='Disabled Poll') + response = self.client.get(reverse('polls-detail', kwargs={'poll_id': + poll.id})) + self.assertEqual(response.status_code, 404) + + def testOld(self): + poll = Poll.objects.get(question='Old Poll') + response = self.client.get(reverse('polls-detail', kwargs={'poll_id': + poll.id})) + self.assertEqual(response.status_code, 200) + + def testActive(self): + poll = Poll.objects.get(question='Active Poll') + response = self.client.get(reverse('polls-detail', kwargs={'poll_id': + poll.id})) + self.assertEqual(response.status_code, 200) + + def testVoteOld(self): + poll = Poll.objects.get(question='Old Poll') + response = self.client.get(reverse('polls-vote', kwargs={'poll_id': + poll.id}), follow=True) + + self.assertEqual(len(response.redirect_chain), 1) + if response.redirect_chain: + self.assertEqual(response.redirect_chain[0][0], + 'http://testserver' + reverse('polls-detail', kwargs={'poll_id': poll.id})) + self.assertEqual(response.redirect_chain[0][1], 302) + + self.assertEqual(response.status_code, 200) + + def testVoteActive(self): + poll = Poll.objects.get(question='Active Poll') + response = self.client.get(reverse('polls-vote', kwargs={'poll_id': + poll.id}), follow=True) + + self.assertEqual(len(response.redirect_chain), 0) + self.assertEqual(response.status_code, 200) + + def testVoteFuture(self): + poll = Poll.objects.get(question='Future Poll') + response = self.client.get(reverse('polls-vote', kwargs={'poll_id': + poll.id}), follow=True) + + self.assertEqual(len(response.redirect_chain), 1) + if response.redirect_chain: + self.assertEqual(response.redirect_chain[0][0], + 'http://testserver' + reverse('polls-detail', kwargs={'poll_id': poll.id})) + self.assertEqual(response.redirect_chain[0][1], 302) + + self.assertEqual(response.status_code, 404) + + def testVoteDisabled(self): + poll = Poll.objects.get(question='Disabled Poll') + response = self.client.get(reverse('polls-vote', kwargs={'poll_id': + poll.id}), follow=True) + + self.assertEqual(response.status_code, 404) + + def testVoteActivePost(self): + self._voteTest() + + def testDeleteVote(self): + poll = self._voteTest() + + response = self.client.post( + reverse('polls-delete_vote'), + {'poll_id': poll.id}, + follow=True) + + self.assertEqual(len(response.redirect_chain), 1) + if response.redirect_chain: + self.assertEqual(response.redirect_chain[0][0], + 'http://testserver' + reverse('polls-detail', kwargs={'poll_id': poll.id})) + self.assertEqual(response.redirect_chain[0][1], 302) + + self.assertEqual(response.status_code, 200) + + choice = Choice.objects.get(pk=1) + self.assertEqual(choice.votes, 0) + self.assertTrue(self.user not in choice.voters.all()) + + def _voteTest(self): + poll = Poll.objects.get(question='Active Poll') + response = self.client.post( + reverse('polls-vote', kwargs={'poll_id': poll.id}), + {'choices': 1}, + follow=True) + + self.assertEqual(len(response.redirect_chain), 1) + if response.redirect_chain: + self.assertEqual(response.redirect_chain[0][0], + 'http://testserver' + reverse('polls-detail', kwargs={'poll_id': poll.id})) + self.assertEqual(response.redirect_chain[0][1], 302) + + self.assertEqual(response.status_code, 200) + + choice = Choice.objects.get(pk=1) + self.assertEqual(choice.votes, 1) + self.assertTrue(self.user in choice.voters.all()) + + return poll
--- a/gpp/polls/urls.py Mon Jun 13 02:19:13 2011 +0000 +++ b/gpp/polls/urls.py Sat Jun 25 23:23:20 2011 +0000 @@ -4,7 +4,6 @@ urlpatterns = patterns('polls.views', url(r'^$', 'poll_index', name='polls-main'), url(r'^(?P<poll_id>\d+)/$', 'poll_detail', name='polls-detail'), - url(r'^(?P<poll_id>\d+)/results/$', 'poll_results', name='polls-results'), url(r'^(?P<poll_id>\d+)/vote/$', 'poll_vote', name='polls-vote'), url(r'^delete_vote/$', 'poll_delete_vote', name='polls-delete_vote'), )
--- a/gpp/polls/views.py Mon Jun 13 02:19:13 2011 +0000 +++ b/gpp/polls/views.py Sat Jun 25 23:23:20 2011 +0000 @@ -2,6 +2,8 @@ Views for the polls application. """ +import datetime + from django.shortcuts import render from django.contrib.auth.decorators import login_required from django.shortcuts import get_object_or_404 @@ -19,8 +21,8 @@ def get_user_choice(user, poll): """ - Return the Choice object the give user voted for from the given poll, - or None of no vote has been recorded (or the user is not authenticated. + Return the Choice object the given user voted for from the given poll, + or None if no vote has been recorded (or the user is not authenticated. """ user_choice = None @@ -45,11 +47,15 @@ def poll_detail(request, poll_id): poll = get_object_or_404(Poll, pk=poll_id) - if not poll.is_enabled: + if not poll.is_enabled or poll.start_date > datetime.datetime.now(): raise Http404 - return render(request, 'polls/poll.html', { + total_votes, choices = poll.results() + + return render(request, 'polls/poll_detail.html', { 'poll': poll, + 'total_votes': total_votes, + 'choices': choices, 'user_choice': get_user_choice(request.user, poll), }) @@ -61,15 +67,18 @@ if not poll.is_enabled: raise Http404 if not poll.is_open(): - return HttpResponseRedirect(reverse('polls-results', args=[poll_id])) + return HttpResponseRedirect(reverse('polls-detail', + kwargs={'poll_id': poll_id})) user_choice = get_user_choice(request.user, poll) if request.method == "POST": - vote_form = VoteForm(poll, request.POST, user=request.user, user_choice=user_choice) + vote_form = VoteForm(poll, request.POST, user=request.user, + user_choice=user_choice) if vote_form.is_valid(): vote_form.save() - return HttpResponseRedirect(reverse('polls-results', args=[poll_id])) + return HttpResponseRedirect(reverse('polls-detail', + kwargs={'poll_id': poll_id})) else: vote_form = VoteForm(poll) @@ -81,18 +90,6 @@ ####################################################################### -def poll_results(request, poll_id): - poll = get_object_or_404(Poll, pk=poll_id) - total_votes, choices = poll.results() - return render(request, 'polls/poll_results.html', { - 'poll': poll, - 'total_votes': total_votes, - 'choices': choices, - 'user_choice': get_user_choice(request.user, poll), - }) - -####################################################################### - @require_POST @login_required def poll_delete_vote(request): @@ -102,4 +99,4 @@ Choice.objects.filter(id=user_choice.id).update(votes=F('votes') - 1) user_choice.voters.remove(request.user) - return HttpResponseRedirect(reverse('polls-results', args=[poll.id])) + return HttpResponseRedirect(reverse('polls-detail', kwargs={'poll_id': poll.id}))
--- a/gpp/templates/polls/latest_poll_tag.html Mon Jun 13 02:19:13 2011 +0000 +++ b/gpp/templates/polls/latest_poll_tag.html Sat Jun 25 23:23:20 2011 +0000 @@ -8,7 +8,7 @@ <li>{{ choice.choice }}</li> {% endfor %} </ul> - <p>Go <a href="{% url 'polls-detail' poll_id=poll.id %}">see the results and vote</a> + <p>Go <a href="{{ poll.get_absolute_url }}">see the results and vote</a> or check out <a href="{% url 'polls-main' %}">more polls</a>.</p> </div> {% endif %}
--- a/gpp/templates/polls/poll.html Mon Jun 13 02:19:13 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -{% extends 'base.html' %} -{% load url from future %} -{% load comment_tags %} -{% block title %}Polls: {{ poll.question }}{% endblock %} -{% block content %} -<h2>Poll</h2> -<h3>{{ poll.question }}</h3> -<ul class="poll-detail"> -{% for choice in poll.choice_set.all %} - <li>{{ choice.choice }}</li> -{% endfor %} -</ul> -{% if user_choice %} -<p>You voted for "{{ user_choice.choice }}".</p> -{% endif %} -{% get_comment_count for poll as comment_count %} -<p> -This poll has {{ poll.total_votes }} vote{{ poll.total_votes|pluralize }} and -<a href="{% url 'polls.views.poll_results' poll.id %}">{{ comment_count }} comment{{ comment_count|pluralize }}</a>. -{% if poll.is_open %} -Voting for this poll started on {{ poll.start_date|date:"F d, Y" }}. - {% if poll.end_date %} - Voting will end on {{ poll.end_date|date:"F d, Y" }}. - {% endif %} -{% else %} -This poll ran from {{ poll.start_date|date:"F d, Y" }} to {{ poll.end_date|date:"F d, Y" }}. -{% endif %} -</p> -<p class="poll-nav"> -<a href="{% url 'polls-results' poll.id %}">View Results & Comments</a> -{% if poll.is_open and user.is_authenticated %} -| <a href="{% url 'polls-vote' poll_id=poll.id %}">Vote</a> -{% endif %} -| <a href="{% url 'polls-main' %}">All Polls</a> -</p> -{% endblock %}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gpp/templates/polls/poll_detail.html Sat Jun 25 23:23:20 2011 +0000 @@ -0,0 +1,63 @@ +{% extends 'base.html' %} +{% load url from future %} +{% load comment_tags %} +{% load script_tags %} +{% block title %}Poll Results: {{ poll.question }}{% endblock %} +{% block custom_css %} +<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/polls.css" /> +{% endblock %} +{% block custom_js %} +{% if poll.is_open %} +<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/comments.css" /> +{% script_tags "markitup jquery-ui" %} +<script type="text/javascript" src="{{ STATIC_URL }}js/comments.js"></script> +{% endif %} +{% endblock %} +{% block content %} +<h2>Polls</h2> +<h3>Results for: {{ poll.question }}</h3> +<dl class="poll-result"> +{% for choice in choices %} + <dt>{{ choice.choice }} - {{ choice.pct|floatformat }}% ({{ choice.votes }} vote{{ choice.votes|pluralize }})</dt> + <dd> + <div class="poll-percent" style="width: {{ choice.pct|floatformat:0 }}%; background-color: teal; color: white;"> + <span> </span></div> + </dd> +{% endfor %} +</dl> +<p><strong>{{ total_votes }} total vote{{ total_votes|pluralize }}.</strong></p> + +{% if user_choice %} +<p>You voted for "{{ user_choice.choice }}".</p> +{% endif %} + +<p> +{% if poll.is_open %} +Voting for this poll started on {{ poll.start_date|date:"F d, Y" }}. + {% if poll.end_date %} + Voting will end on {{ poll.end_date|date:"F d, Y" }}. + {% endif %} +{% else %} +This poll ran from {{ poll.start_date|date:"F d, Y" }} to {{ poll.end_date|date:"F d, Y" }}. +{% endif %} +</p> + +<p class="poll-nav"> +{% if poll.is_open and user.is_authenticated %} +<a href="{% url 'polls-vote' poll_id=poll.id %}">Vote</a> +{% endif %} +| <a href="{% url 'polls-main' %}">All Polls</a> +</p> + +{% get_comment_count for poll as comment_count %} +<p>This poll has <span id="comment-count">{{ comment_count }}</span> comment{{ comment_count|pluralize }}.</p> +<hr /> +{% render_comment_list poll %} +{% if poll.is_open %} +<p>Leave a comment?</p> +{% render_comment_form for poll %} +{% else %} +<p>Comments are closed for this poll. If you'd like to share your thoughts on this poll +with the site staff, you can <a href="{% url 'contact-form' %}">contact us directly</a>.</p> +{% endif %} +{% endblock %}
--- a/gpp/templates/polls/poll_results.html Mon Jun 13 02:19:13 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -{% extends 'base.html' %} -{% load url from future %} -{% load comment_tags %} -{% load script_tags %} -{% block title %}Poll Results: {{ poll.question }}{% endblock %} -{% block custom_css %} -<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/polls.css" /> -<link rel="stylesheet" type="text/css" href="{{ STATIC_URL }}css/comments.css" /> -{% endblock %} -{% block custom_js %} -{% if poll.is_open %} -{% script_tags "markitup jquery-ui" %} -<script type="text/javascript" src="{{ STATIC_URL }}js/comments.js"></script> -{% endif %} -{% endblock %} -{% block content %} -<h2>Polls</h2> -<h3>Results for: {{ poll.question }}</h3> -<dl class="poll-result"> -{% for choice in choices %} - <dt>{{ choice.choice }} - {{ choice.pct|floatformat }}% ({{ choice.votes }} vote{{ choice.votes|pluralize }})</dt> - <dd> - <div class="poll-percent" style="width: {{ choice.pct|floatformat:0 }}%; background-color: teal; color: white;"> - <span> </span></div> - </dd> -{% endfor %} -</dl> -<p><strong>{{ total_votes }} total vote{{ total_votes|pluralize }}.</strong></p> - -{% if user_choice %} -<p>You voted for "{{ user_choice.choice }}".</p> -{% endif %} - -<p class="poll-nav"> -<a href="{{ poll.get_absolute_url }}">Poll Details</a> -{% if poll.is_open and user.is_authenticated %} -| <a href="{% url 'polls-vote' poll_id=poll.id %}">Vote</a> -{% endif %} -| <a href="{% url 'polls-main' %}">All Polls</a> -</p> - -{% get_comment_count for poll as comment_count %} -<p>This poll has <span id="comment-count">{{ comment_count }}</span> comment{{ comment_count|pluralize }}.</p> -<hr /> -{% render_comment_list poll %} -{% if poll.is_open %} -<p>Leave a comment?</p> -{% render_comment_form for poll %} -{% else %} -<p>Comments are closed for this poll. If you'd like to share your thoughts on this poll -with the site staff, you can <a href="{% url 'contact-form' %}">contact us directly</a>.</p> -{% endif %} -{% endblock %}
--- a/gpp/templates/polls/poll_vote.html Mon Jun 13 02:19:13 2011 +0000 +++ b/gpp/templates/polls/poll_vote.html Sat Jun 25 23:23:20 2011 +0000 @@ -24,9 +24,8 @@ </form> {% endif %} <p class="poll-nav"> -<a href="{{ poll.get_absolute_url }}">Poll Details</a> -| <a href="{% url 'polls-results' poll.id %}">View Results</a> -| <a href="{% url 'polls-main' %}">All Polls</a> +<a href="{{ poll.get_absolute_url }}">View results</a> +| <a href="{% url 'polls-main' %}">All polls</a> </p> <p>This poll was published on {{ poll.start_date|date:"F d, Y" }}.</p> {% endblock %}