Commits

Kenneth Love committed e6d5b13

added pollaxe back

  • Participants
  • Parent commits 296c808

Comments (0)

Files changed (19)

pollaxe/__init__.py

+# -*- coding: utf-8 -*-
+"""
+See PEP 386 (http://www.python.org/dev/peps/pep-0386/)
+
+Release logic:
+1. Remove the "dev" part from current, save file.
+2. git commit
+3. git tag <version>
+4. push to pypi + push to github
+5. bump the version, append '.dev0'
+6. git commit
+7. push to github (to avoid confusion)
+"""
+__version__ = '0.0.0.dev0'
+

pollaxe/manage.py

+#!/usr/bin/env python
+from django.core.management import execute_manager
+try:
+    import settings # Assumed to be in the same directory.
+except ImportError:
+    import sys
+    sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
+    sys.exit(1)
+
+if __name__ == "__main__":
+    execute_manager(settings)

pollaxe/polls/__init__.py

Empty file added.

pollaxe/polls/admin.py

+import datetime
+
+from django.contrib import admin
+
+from polls.models import Poll, Choice
+
+
+class PollAdmin(admin.ModelAdmin):
+        fieldsets = [
+            (None,               {'fields': ['question']}),
+            ('Date information', {'fields': ['pub_date']}),
+        ]
+
+class ChoiceInline(admin.StackedInline):
+    model = Choice
+    extra = 3
+
+class PollAdmin(admin.ModelAdmin):
+    fieldsets = [
+        (None,               {'fields': ['question']}),
+        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
+    ]
+    inlines = [ChoiceInline]
+    list_display = ('question', 'pub_date',)# 'was_published_today')
+    
+    #def was_published_today(self):
+    #    return self.pub_date.date() == datetime.date.today()
+        
+    #was_published_today.short_description = 'Published today?'    
+
+admin.site.register(Poll, PollAdmin)

pollaxe/polls/models.py

+import datetime 
+from django.db import models
+
+class Poll(models.Model):
+    """An individual poll to be tested"""
+    question = models.CharField(max_length=200)
+    pub_date = models.DateTimeField('date published')
+    
+    def __unicode__(self):
+        return self.question
+    
+    def was_published_today(self):
+        return self.pub_date.date() == datetime.date.today()
+
+class Choice(models.Model):
+    """Choices on a poll"""
+    poll = models.ForeignKey(Poll)
+    choice = models.CharField(max_length=200)
+    votes = models.IntegerField()
+    
+    def __unicode__(self):
+        return self.choice    

pollaxe/polls/tests/__init__.py

+from polls.tests.test_models import *
+from polls.tests.test_views import *

pollaxe/polls/tests/test_models.py

+from datetime import datetime, timedelta
+
+from django.contrib.auth.models import User
+from django.test import TestCase
+
+from polls.models import Choice, Poll
+from polls.tests.utils import BaseTestCase
+
+class TestPolls(BaseTestCase):
+    
+    
+    def test_poll_create(self):
+        """ Can we create a poll?
+        
+        * Seems trivial now
+        * But for complex systems what started out as a simple create can get complex
+        * Get your test coverage up!
+        """                
+        
+        poll_count = Poll.objects.count()
+        poll = Poll(
+            question="Why is Python awesome?",
+            pub_date=datetime.now()
+        )
+        poll.save()
+        self.assertTrue(poll_count < Poll.objects.count())
+        
+    def test_was_published_today(self):
+        
+        poll = Poll(
+            question="Django is for the internets",
+            pub_date=datetime.now()
+        )
+        poll.save()
+        self.assertTrue(poll.was_published_today())
+        
+        poll.pub_date = datetime.now() - timedelta(days=3)
+        poll.save()
+        
+        self.assertFalse(poll.was_published_today())

pollaxe/polls/tests/test_views.py

+from datetime import datetime, timedelta
+
+from django.core.urlresolvers import reverse
+from django.contrib.auth.models import User
+from django.test import TestCase
+
+from polls.models import Choice, Poll
+from polls.tests.utils import BaseTestCase
+
+class TestPollSample(BaseTestCase):
+    
+    def setUp(self):
+        super(TestPollSample,self).setUp()
+        self.poll = Poll(
+            question="What is your favorite number?",
+            pub_date=datetime.now()
+        )
+        self.poll.save()
+        for i in range(1, 4):
+            choice = Choice(
+                poll = self.poll,
+                choice=str(i),
+                votes=0
+            )
+            choice.save()        
+    
+    
+    def test_poll_index(self):
+        """ Check if the poll index displays """        
+        
+        # Now display me a poll!
+        url = reverse("poll_index")
+        response = self.client.get(url)
+        
+        # Show them the print!
+        #print response
+        
+        self.assertContains(response, "What is your favorite number?")
+        
+    def test_poll_detail(self):
+        """ Check if the poll detail displays """
+        
+        # Grab poll again to make sure we get right ID and that
+        #   any custom save methods have been fully fired
+        poll = Poll.objects.get(id=self.poll.id)
+        
+        url = reverse("poll_detail", kwargs={"poll_id": poll.id})
+        response = self.client.get(url)
+        
+        self.assertContains(response, "What is your favorite number?")        
+        
+    def test_poll_vote(self):
+        """ vote on a poll """
+        url = reverse("poll_vote", kwargs={"poll_id": self.poll.id})
+        
+        # Pick a bad choice out of range
+        data = dict(choice = 10)
+        response = self.client.post(url, data, follow=True)
+        self.assertContains(response, "You didn&#39;t select a choice.")
+        
+        # pick a choice in range
+        data = dict(choice = 2)
+        response = self.client.post(url, data, follow=True)
+        self.assertContains(response, "<li>2 -- 1 vote</li>")
+        

pollaxe/polls/tests/utils.py

+from django.contrib.auth.models import User
+from django.test import TestCase
+      
+
+class BaseTestCase(TestCase):
+    
+    urls = 'polls.urls'    
+    
+    def setUp(self):
+        """ Provides a self.user and self.user_pw
+        
+        usage::
+
+            from polls.tests.utils import BaseTestCase
+            class MyTest(BaseTestCase):
+
+                def setUp(self):
+                    super(MyTest,self).setUp()                
+                    # stick in custom setUp bits here
+                    # stick in custom setUp bits here
+                    # stick in custom setUp bits here                                
+                """
+
+        # I always forget the password
+        self.user_pw = 'test'
+
+        # Create a sample user
+        self.user = User.objects.create_user('pydanny','pydanny@test.com',self.user_pw,)
+        self.user.first_name = "Danny"
+        self.user.last_name = "Greenfeld"
+        self.user.save()
+        
+    def tearDown(self):
+        self.client.logout()
+        
+    def login(self, user, password):
+        return login(self, user, password)

pollaxe/polls/urls.py

+from django.conf.urls.defaults import patterns, url
+
+from polls import views
+
+urlpatterns = patterns('',
+
+    url(
+        regex=r'^$',
+        view=views.index,
+        name='poll_index',
+    ),
+
+    url(
+        regex=r'^(?P<poll_id>\d+)/$',
+        view=views.detail,
+        name='poll_detail',
+    ),
+    
+    url(
+        regex=r'(?P<poll_id>\d+)/results/$',
+        view=views.results,
+        name='poll_results'
+    ),
+    
+    url(
+        regex=r'(?P<poll_id>\d+)/vote/$',
+        view=views.vote,
+        name='poll_vote'
+    ),
+    
+    # DON'T DO THIS!!!
+    # This is a tuple and hence takes moar smartz to read
+    # I call this 'baby obfuscated code'
+    #(r'^blarg/$', views.poll_detail, "poll_detail")
+    
+    # DON'T DO THIS!!!
+    # This is less explicit view call and Django has to do 'magic' to make it work
+    # This means your stacktrace for generated bugs is longer
+    # I call this 'making your code harder to debug'
+    #url(
+    #    regex=r'^(?P<poll_id>\d+)/$',
+    #    view="polls.views.poll_detail",
+    #    name='poll_detail',
+    #),
+    
+)
+

pollaxe/polls/views.py

+from django.core.urlresolvers import reverse
+from django.http import HttpResponse, HttpResponseRedirect
+from django.shortcuts import render_to_response, get_object_or_404
+from django.template import Context, loader, RequestContext
+
+from polls.models import Poll, Choice
+
+POLL_DETAIL_TEMPLATE = "polls/detail.html"
+
+# We pass the template_name as a variable because it makes the template function easier to 
+# identify AND because it means it can be changed on the fly
+def index(request, template_name="polls/index.html"):
+    """ Show a list of polls"""
+    latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
+    return render_to_response(template_name, {'latest_poll_list': latest_poll_list})
+
+
+def detail(request, poll_id, template_name=POLL_DETAIL_TEMPLATE):
+    """ Show detail on a poll"""    
+    
+    # I used 'poll' instead of 'p' because the pixel shortage is over.
+    # If this is too much typing, then just cut-and-paste, okay?
+    poll = get_object_or_404(Poll, pk=poll_id)
+    choices = Choice.objects.filter(poll=poll)
+    return render_to_response(template_name, {
+        'poll': poll,
+        'choices': choices }, 
+        context_instance=RequestContext(request))    
+
+def vote(request, poll_id, template_name=POLL_DETAIL_TEMPLATE):
+    """ user votes on a poll"""
+
+    poll = get_object_or_404(Poll, pk=poll_id)
+    try:
+        selected_choice = poll.choice_set.get(pk=request.POST['choice'])
+    except (KeyError, Choice.DoesNotExist):
+        # Redisplay the poll voting form.
+        return render_to_response(template_name, {
+            'poll': poll,
+            'error_message': "You didn't select a choice.",
+        }, context_instance=RequestContext(request))
+    else:
+        selected_choice.votes += 1
+        selected_choice.save()
+        # Always return an HttpResponseRedirect after successfully dealing
+        # with POST data. This prevents data from being posted twice if a
+        # user hits the Back button.
+        url = reverse('poll_results', args=(poll.id,))
+        return HttpResponseRedirect(url)
+        
+def results(request, poll_id, template_name="polls/results.html"):
+    poll = get_object_or_404(Poll, pk=poll_id)
+    return render_to_response(template_name, 
+        {'poll': poll},
+        context_instance=RequestContext(request)
+        )
+        
+        

pollaxe/settings/__init__.py

Empty file added.

pollaxe/settings/base.py

+# Django settings for pollaxe project.
+
+import os
+
+settings_dir = os.path.dirname(__file__)
+PROJECT_ROOT = os.path.abspath(os.path.dirname(settings_dir))
+
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+    #('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+        'NAME': 'base.db',                      # Or path to database file if using sqlite3.
+        'USER': '',                      # Not used with sqlite3.
+        'PASSWORD': '',                  # Not used with sqlite3.
+        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
+        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
+    }
+}
+
+TIME_ZONE = 'America/Chicago'
+
+LANGUAGE_CODE = 'en-us'
+
+SITE_ID = 1
+
+USE_I18N = True
+
+USE_L10N = True
+
+MEDIA_URL = '/media/'
+MEDIA_ROOT = os.path.realpath(os.path.join(PROJECT_ROOT, "media"))
+
+STATIC_URL = '/static/'
+STATIC_ROOT = os.path.realpath(os.path.join(PROJECT_ROOT, "static"))
+
+ADMIN_MEDIA_PREFIX = '/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = '<make-me-unique>'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+    'django.template.loaders.filesystem.Loader',
+    'django.template.loaders.app_directories.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+    'django.middleware.common.CommonMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+)
+
+ROOT_URLCONF = 'pollaxe.urls'
+
+TEMPLATE_DIRS = (
+    os.path.join(PROJECT_ROOT, "templates"),
+)
+
+PREREQ_APPS = (
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.sites',
+    'django.contrib.messages',
+    'django.contrib.admin',
+)
+
+PROJECT_APPS = (
+    'polls',
+)
+
+INSTALLED_APPS = PREREQ_APPS + PROJECT_APPS
+
+TEST_RUNNER = 'testrunner.OurCoverageRunner'
+
+COVERAGE_MODULE_EXCLUDES = [
+    'tests$', 'settings$', 'urls$', 'locale$',
+    'migrations', 'fixtures', 'admin$',
+]
+COVERAGE_MODULE_EXCLUDES += PREREQ_APPS
+COVERAGE_REPORT_HTML_OUTPUT_DIR = "coverage"
+
+HTML_OUTPUT_DIR = os.path.join(PROJECT_ROOT, "coverage")
+
+LOGGING = {
+    'version': 1,
+    'disable_existing_loggers': False,
+    'handlers': {
+        'mail_admins': {
+            'level': 'ERROR',
+            'class': 'django.utils.log.AdminEmailHandler',
+        }
+    },
+    'loggers': {
+        'django.request': {
+            'handlers': ['mail_admins'],
+            'level': 'ERROR',
+            'propagate': True,
+        },
+    },
+}
+

pollaxe/settings/dev.py

+from base import *
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
+        'NAME': 'overload.db',          # Or path to database file if using sqlite3.
+        'USER': '',                      # Not used with sqlite3.
+        'PASSWORD': '',                  # Not used with sqlite3.
+        'HOST': '',                      # Set to empty string for localhost. Not used with sqlite3.
+        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
+    }
+}

pollaxe/templates/polls/detail.html

+<h1>{{ poll.question }}</h1>
+
+{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
+
+<form action="{% url poll_vote poll.pk %}" method="post">
+{% csrf_token %}
+{% for choice in poll.choice_set.all %}
+    <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
+    <label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
+{% endfor %}
+<input type="submit" value="Vote" />
+</form>

pollaxe/templates/polls/index.html

+<h1>Show me polls</h1>
+
+{% if latest_poll_list %}
+    <ul>
+    {% for poll in latest_poll_list %}
+        <li><a href="{% url poll_detail poll.pk %}">{{ poll.question }}</a></li>
+    {% endfor %}
+    </ul>
+{% else %}
+    <p>No polls are available.</p>
+{% endif %}

pollaxe/templates/polls/results.html

+<h1>{{ poll.question }}</h1>
+
+<ul>
+{% for choice in poll.choice_set.all %}
+    <li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
+{% endfor %}
+</ul>
+
+<a href="{% url poll_detail poll.pk %}">Vote again?</a>

pollaxe/testrunner.py

+# Make our own testrunner that by default only tests our own apps
+
+from django.conf import settings
+from django.test.simple import DjangoTestSuiteRunner
+from django_coverage.coverage_runner import CoverageRunner
+
+# TODO write something that generates a coverage folder if it doesn't already exist
+
+class OurTestRunner(DjangoTestSuiteRunner):
+    def build_suite(self, test_labels, *args, **kwargs):
+        return super(OurTestRunner, self).build_suite(test_labels or settings.PROJECT_APPS, *args, **kwargs)
+
+class OurCoverageRunner(OurTestRunner, CoverageRunner):
+    pass
+from django.conf.urls.defaults import *
+
+
+from django.contrib import admin
+admin.autodiscover()
+
+urlpatterns = patterns('',
+
+    (r'^admin/', include(admin.site.urls)),
+    (r'^', include("polls.urls")),    
+    
+)