A Simple Poll Manager with Django

Created By: Jesse Slavens on April 30th, 2012

In this tutorial I’ll be showing you how to make a simple poll manager using Django, a Python framework.

Table of Contents

  1. Setting up the database
  2. Changing the Time Zone
  3. Specifying Your Template Directory
  4. Specifying Installed Apps
  5. Setting Up the Database
  6. Creating the Polls Model
  7. Creating the Choices Model
  8. Creating the Votes Model
  9. Poll Form
  10. Choice form
  11. Imports for views.py
  12. Index Page
  13. Adding Polls
  14. Adding Choices
  15. Viewing a List of All Active Polls
  16. Viewing a Single Poll
  17. Adding Votes to the Database
  18. Displaying the Results
  19. Testing Out Your Site

Getting Started

In this tutorial I’ll be showing you how to make a simple poll manager using Django, a Python framework.

To complete this tutorial, you’re going to need to have:

  • A basic understanding of the Python programming language
  • Django installed on your server

If you’ve never used Python before, or if you feel you need to brush up on your Python skills, you should check out http://learnpythonthehardway.org/book/.

If you need to install Django on a server, follow this tutorial to get yourself started: https://docs.djangoproject.com/en/dev/topics/install/?from=olddocs

Starting Your Project

Once you’ve got Django installed, the first thing you’re going to need to do is open up your command line (Command Prompt in Windows or Terminal in Mac) and cd to the folder you want to start your project in. From here, we want to run the following command to start our Django project:

django-admin.py startproject poll_manager

Note that poll_manager is the name of your project, and can be changed to whatever you want it to be named.

The next step is to create the poll manager app. To do this, you need to cd into the poll_manager directory and run the following code in command line:

python manage.py startapp polls

Running this command will create a folder called polls containing three files: views.py, models.py, and test.py. We will be working with views.py and models.py.

Configuring settings.py

Setting up the database

With your favorite text editor, navigate to your poll_manager folder and open up settings.py. The first thing we’re going to do here is set up our database, so head down to the section that says DATABASES and enter the following information:

‘ENGINE’: ‘django.db.backends.mysql’,
‘NAME’: ’localhost’,
‘USER’: ’root’,
‘PASSWORD’: ‘’,
‘HOST’: ‘’,
‘PORT’:’’,

Note that this information may vary depending on how you have your server set up.

Changing the Time Zone

Next we’re going to change the TIME_ZONE setting to whichever time zone you’re currently in (for example, North American east coast time would be 'America/New_York'). A list of the time zone names can be found here http://en.wikipedia.org/wiki/List_of_tz_zones_by_name.

Specifying Your Template Directory

The next thing we’re going to do is specify which directory our template files are going to be. The first thing we need to do is create a directory called “templates” in the poll_manager directory. When that’s completed, head back to your settings.py files and scroll down to TEMPLATE_DIRS. Here you need to put in the file path to the templates folder, which might look something like:

'/home/ public_python/poll_manager/templates'

or

‘C:/www/poll_manager/templates’

Specifying Installed Apps

Finally, we need to scroll down to INSTALLED_APPS and do two things:

  • Comment out 'django.contrib.auth'
  • Add 'polls' to the bottom of the list

We don’t necessarily need the auth app for this tutorial, so we’re commenting it out to save some database space. Adding ‘polls’ to the bottom will enable the polls app we’re building to work on the website we will be creating.

Setting Up Models

Head into your “polls” app folder and open up models.py. The first thing we need to do is import two modules into the file, so put the following code at the top of your document:

from django.db import models
from django.forms import ModelForm 

These two lines will enable the use of models and model forms in your document.

Setting Up the Database

Now it’s time to set up our database. The first thing we need to do is create a new database in phpmyadmin. For the sake of this tutorial, let’s name it "polls."

Creating the Polls Model

Next, it’s time to set up our tables. Let’s head back over to models.py and make the table for the actual poll. We’re going to want this table to contain two colums; the name of the question and the date the poll was created. To do this, we write the following code:

class Poll(models.Model):
        question = models.CharField(max_length=255)
        date = models.DateTimeField(auto_now_add=True)
    
        def __unicode__(self):
            return self.question

This model is set up to do a couple things:

  • Creates a colums named “question” with a max length of 255 characters
  • Creates a column named “date” that automatically adds the current date and time when the user creates a poll

Creating the Choices Model

Now we’re going to create a model for our choices. For this model, we’re going to use the “Poll” model as a foreign key and create a choice column to store the choices for our polls. Insert the following lines of code into your “models.py” document:

class Choice(models.Model):
        poll = models.ForeignKey(Poll)
        choice = models.CharField(max_length=255, blank=True)

This model looks very similar to the last one, with a couple very minor changes. As you can see, we set up “poll” as a foreign key for the “Poll” model, and added a choice column that accepts a max length of 255 characters.

Creating the Votes Model

Now that we have a table to house our polls and choices, we need a new table to keep track of votes. To do this, we’re going to create two columns in this table that are foreign keys of the other two models we’ve created. The code for this model looks like this:

class Votes(models.Model):
        poll = models.ForeignKey(Poll)
        choiceVote = models.ForeignKey(Choice)

We’ve created our models…now what? The next step is to create forms that relate to these models, which Django makes incredibly easy. There are two ways to create forms in Django; you can create a forms.py page and create your forms there, or you can create something called a Model Form in models.py. For this tutorial, we’re going to do the latter.

Poll Form

For this poll manager, we’re only going to need two forms – one to create polls and another to add choices to your poll. First, let’s create the model form for the “Poll” model:

class PollForm(ModelForm):
        class Meta:
            model = Poll

Here’s what we just did:

  • We created a model form called PollForm, which we can later call to use in our views
  • We declared that this form is going to use metadata from the model named Poll

Choice form

Next up, we’re going to create the form to input choices. The code for this looks exactly like the code we used to create “PollForm”, with one small difference:

class ChoiceForm(ModelForm):
        class Meta:
        model = Choice
        fields = ('choice',)

The “fields” option lets us choose which input fields we want the form to display. Alternatively, we could have written exclude = (poll,), which would have essentially done the same thing.

Setting up the Views, Templates, and URLs

Now that we have our database, models, and forms set up, we can go ahead and write our views. We’re also going to be creating our templates and URLs for our views simultaneously.

Imports for views.py

Open up views.py and add this to the top of the page. These are the modules we’re going to be using for this tutorial:

from django.http import HttpResponseRedirect, HttpResponse
from django.template import Context, loader, RequestContext
from django.shortcuts import render_to_response, render
from models import Poll, Choice, Votes, PollForm, ChoiceForm

Index Page

The index page is going to be very short and sweet. Let’s head to views.py and add the following code:

def index(request):
        return render_to_response('index.html', context_instance = RequestContext(request),)

All we’re doing in this view is linking it to a template. Now let’s open up urls.py and add the following URL:

url(r'^$', 'poll_tutorial.polls.views.index', name = 'index'),

Finally, let’s set up our template. Create a document called index.html and add the following. The code for this is going to be short and sweet:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Poll Manager Home</title>
</head>
<body>

    <p>Welcome!</p> 
    <p><a href="{% url polls %}">View Polls</a></p>
    <p><a href="{% url add_poll %}">Add a poll</a></p>  
        
</body>
</html>

This is going to break our website when we try to run it until we write our views and URLs for adding and viewing polls, but that’s okay! We’ll get to that soon enough.

Adding Polls

Alrighty, it’s time to set the page we’re going to use to create polls. Let’s start with the view:

def add_poll(request):
        #calls the PollForm we created and displays it on the page
        if request.method == 'POST':
            form = PollForm(request.POST)
            if form.is_valid():
                form.save() 
                return HttpResponseRedirect('../.')
        else:
            form = PollForm()
        return render_to_response ('add_poll.html', {'form': form}, context_instance = RequestContext(request),)

Everything here is pretty straight-forward. By default, the page loads up the PollForm. On submit, it checks and sees if the form is valid and saves the information if it is and redirects them to the add_choices page. If it isn’t, the form gets reloaded.

Now it’s time to add the URL for this view. Open up urls.py and write this code under the url for the index:

url(r'^add_poll/$', 'poll_tutorial.polls.views.add_poll', name = 'add_poll'),

To wrap up this view, we need to complete the template for it. Create a new HTML file and add the following code:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Add a Poll</title>
</head>
<body>

    <p>Add a Poll</p>
    <form name="addPoll" action "/add_choices/" method="post"> {% csrf_token %}
        <fieldset>     
                    <label id="questionID" for="id_question">Question:</label> {{form.question}}
            <input id="submit" type="submit" value="Submit" />
        </fieldset>
    </form>
        
</body>
</html>

This template is also pretty straight forward. We have a form with an input field which we call from Django (which, if you look, is the question field in the Poll table). When the form is submitted, Django saves whatever was in the input field into our database.

Adding Choices

Since we can now create polls we’re going to need the option to add choices to it. Open up views.py and add the following code:

def add_choice(request, poll_id):
        poll = Poll.objects.get(id = poll_id)
        if request.method =='POST':
            form = ChoiceForm(request.POST)
            if form.is_valid():
                # uses false commit to save the poll as the current poll ID, sets the initial vote to 0, and saves all choices the user
                # has put in the form
                add_poll = form.save(commit = False)
                add_poll.poll = poll
                add_poll.vote = 0
                add_poll.save()         
                form.save()
            return HttpResponseRedirect('../')
        else: 
            form = ChoiceForm()
        return render_to_response ('add_choices.html', {'form': form, 'poll_id': poll_id,}, 
                                context_instance = RequestContext(request),)

Here’s what we’re doing in this view:

  • The first thing we’re doing is pulling the current poll ID from the URL. This allows us to save the poll ID to a variable and input that variable into the database.
  • Next, we attempt to save the information in the form to the database.
    • If the form is valid, we’re going to use a false commit to save multiple values into the database. We’re saving the poll ID number into the database as well as initializing the vote count to 0.
    • If the form is not valid (as seen in the else statement), the page gets reloaded and the form is wiped clean.

If the form is valid and the data is accepted, the user is redirected to the page where the poll’s information is displayed.

Now that we have out view set up, let’s add the following to urls.py:

url(r'^polls/(?P<poll_id>\d+)/add_choices/$', 'poll_tutorial.polls.views.add_choice', name = 'add_choice'),

This url is a little different from the previous two. The difference here is (?P<poll_id>\d+), which allows us to add (and extract) the poll ID to the url.

To wrap this view up, we need to create the template for it. This template is going to look exactly like the add_polls template we created earlier:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Add a Poll</title>
</head>>
<body>
    <p>Add Choices</p>
    <form id="choice" name="" action="" method="post"> {% csrf_token %}
        <fieldset>
            <label for="id_choice">Choice: </label>{{form.choice}}
        
            <input id="submit" type="submit" value="Submit" />
        </fieldset>
    </form>

</body>
</html>

Viewing a List of All Active Polls

Great! We’ve created a poll and added choices to it! But now we need a page to display the poll we just created, as well as any other poll we might create in the future. Let’s open up views.py and add the following:

def view_polls(request):
        poll_query = Poll.objects.all().order_by('date')
        return render_to_response('polls.html',{'poll_query': poll_query, })

This view is very simple – all it does is makes a query that grabs all the polls in the database and displays them by date created. Now let’s make the url for it:

url(r'^polls/$', 'poll_tutorial.polls.views.view_polls', name = 'polls'),

Finally, let’s create the template for it:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Vote!</title>
</head>
<body>
    <p>Here's a list of polls</p>
    {% if poll_query %}
    <ul>
        {% for poll in poll_query %}
            <li><a href='{{poll.id}}/'>{{poll.question}}</a></li>
        {% endfor %}
    </ul>
    {% else %}
        <p>There are no polls available.</p>   
    {% endif %}

</body>
</html>

Here’s a quick rundown of what’s going on in this template:

  • Essentially what we’re doing is checking if there are any polls in the database.
    • If there are polls in the database, an unordered list is created and lists all the polls in the database as a link (we’ll be using these links later)
    • If there are no polls in the database, a paragraph stating “there are no polls available” is displayed.

Viewing a Single Poll

Remember those links we created on the polls page in the last section? Now we’re going to use internet sworcery to make them do stuff! Open up views.py and add the following:

def view_single_poll(request, poll_id): 
        poll = Poll.objects.get(id=poll_id)
        choices = poll.choice_set.all().order_by('id')
        return render_to_response('poll_info.html', {'poll': poll, 'choices':choices,}, context_instance = RequestContext(request),)

This view (coupled with the template) creates a page where the title, choices, and results (eventually) will be displayed for a single poll. Now let’s add the URL for it:

url(r'^polls/(?P<poll_id>\d+)/$','poll_tutorial.polls.views.view_single_poll'),

And finally, let’s create the template:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Add a Poll</title>
</head>
<body>
    <p><a href="add_choices/">Add choices</a></p>
    <p><a href="vote/">Click here to vote</a></p>
    {% for choice in choices %}
        <p class="resultsList">{{choice.choice}} - {{choice.votes_set.count}}</p>
    {% endfor %}
        
</body>
</html>

Here’s a quick rundown of what’s going on in this template:

  • At the top of the page, we have two links – one linking to the add choices page we created earlier and other that will lead us to a page where we can vote on the poll.
  • Under the links is a for loop that goes through the choices for the poll and displays them along with the number of votes for that choice.

Adding Votes to the Database

Okay, now that we have our polls and choices set up, we need to set up a way to vote. Open up views.py and add the following view:

def add_vote(request, poll_id):
        poll = Poll.objects.get(id=poll_id) 
        choice = Choice.objects.filter(poll=poll_id).order_by('id')
        if request.method == 'POST':
            vote = request.POST.get('choice')
            if vote:
                vote = Choice.objects.get(id=vote)  
                #saves the poll id, user id, and choice to the Votes table
                v = Votes(poll=poll, choiceVote = vote)
                v.save()
                #redirects the user to the results page after they submit their vote
                return HttpResponseRedirect('../')
        return render_to_response('votes.html',{'choice': choice, 'poll': poll, 'vcount': vcount,}, context_instance=RequestContext(request))

Here’s what this view does:

  • First, it grabs the poll ID from the URL
  • Next, we use a query to get all the choices in the poll and display them by ID (which is the same as date created in this case)
  • On form submit, django saves whatever choice in checked in the form to the variable “vote”
  • If the user chose a vote, django then saves the poll ID and the choice ID into the database, and then returns the user to the previous page (poll_info.html)

URL time! Throw this bad boy into urls.py:

url(r'^polls/(?P<poll_id>\d+)/vote/$', 'poll_tutorial.polls.views.add_vote', name = 'vote'),

Let’s wrap this baby up, template style!

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <title>Vote!</title>
</head>
<body>
    <p>{{poll.question}}</p>
    {% if choice %}
    <form method="post" action="" id="voteForm">{% csrf_token %}
        <fieldset>
            {% for choice in choice %}
                <p><input type="radio" name="choice" id="choice" value="{{choice.id}}" />
                <label for="choice{{forloop.counter>{{choice.choice}}</label></p>
            {%endfor%}
                
            <input type="submit" id="submit" value="Submit" />
        </fieldset>
            
    </form>
    {% else %}
    <p class="noChoice">No votes have been added to this poll yet!</p>
    {% endif %}


</body>
</html>

In layman’s terms:

  • First we check if there are any choices in the database for this particular poll.
  • If the poll does have choices, we display the form.
  • We use a for loop to loop through and display every choice for this poll as an option with a radio button next to it.
  • If there are no choices in the database, an error message (shown in the if statement) is displayed on the screen.

Displaying the Results

Final stretch! We’ve already set up the template for the results (in poll_info.html), so all we have to write is the view:

def view_results(request, poll_id):
        # displays the choices and the number of votes they have - diaplaying the number of votes is done in the view_results template
        poll = Poll.objects.get(id=poll_id)
        choices = poll.choice_set.all()
        return render_to_response('poll_info.html', vars())

Testing Out Your Site

And there we have it! Now start your command line, navigate to your project folder, and enter the following command:

python manage.py runserver

Your command prompt should now print an address that you can copy and paste in your browser. Vola! A working poll manager!