The Little Things (TLT): Django - Creating a Drop-Down List with Django

I decided that I'd start a series called "The Little Things" to get back into blogging. I've been developing Polydoo.com, a modern way to consider classified ads as bite-sized ad listings. During development, I've learned a lot about the foundations of different technologies. Polydoo is being written mostly using the Django framework, which is all Python. I, not being as seasoned in Python dev as I want to be, am challenging myself to blog every 2 days on something new, starting today.

Since I like simple things, including simple ways to complete tasks, my posts will normally be really short. Most of them will leave much to the imagination to readers like you, which may spark an urge to delve deeper into what I've written about. That's a great thing. I encourage you to do that, since by the time I've posted, I've already began that delving process. Therefore, consider these "Greg's Notes" in different areas on development.

Here it goes: Creating a Drop-Down List with Django

Polydoo.com's design is based on a few core philosophies regarding ease-of-use. One of them is that a user should be able to get to each part of the site within less than 5 clicks. Therefore, it's important that forms are designed in a way that keeps the user focused on getting their job done very quickly.

I was writing code for two of the five major forms on the website. Initially, I was going to have a character input field for one of the values I'm storing inside of the database. But after thinking about how hard it is for me to think of tags that are already registered on StackOverflow when I first register, I decided to create a pre-generated list full of possible values the user may want to use for the field in question. Since there are less than 40 options, I decided to create a drop-down selection list.

For the forms, I decided to use ModelForms for the ad posting and ad waitlist forms. I figured it'd be easier for me to manage the data being stored throughout code if I tied forms to models.

To create a drop-down list field, you do the following:

  1. Create a tuple of tuples containing db-entry:label pairs in your model or somewhere you can reference this list (the tuples).
  2. Create a model containing the model for your incoming database entries from the form-to-be.
  3. Inside the model of the input field which'll be your ChoiceField, set choices=<name of tuple of tuples>
  4. In your ModelForm, set <model field name> = forms.ChoiceField(choices=<name of tuple of tuples>)
  5. In your template, render the form as you would depending on your view.

Here's a full code example of how I did it:

models.py

from django.db import models

CATEGORIES = (  
    ('LAB', 'labor'),
    ('CAR', 'cars'),
    ('TRU', 'trucks'),
    ('WRI', 'writing'),
)
LOCATIONS = (  
    ('BRO', 'Bronx'),
    ('BRK', 'Brooklyn'),
    ('QNS', 'Queens'),
    ('MAN', 'Manhattan'),
    ('STN', 'Staten Island'),
)

class PostAd(models.Model):  
    name        = models.CharField(max_length=50)
    email       = models.EmailField()
    gist        = models.CharField(max_length=50)
    category    = models.CharField(max_length=3, choices=CATEGORIES)
    location    = models.CharField(max_length=3, choices=LOCATIONS)
    description = models.TextField(max_length=300)
    expire      = models.DateField()

 forms.py

from django import forms  
from .models import PostAd, DooSomething

CATEGORIES = (  
    ('LAB', 'labor'),
    ('CAR', 'cars'),
    ('TRU', 'trucks'),
    ('WRI', 'writing'),
)
LOCATIONS = (  
    ('BRO', 'Bronx'),
    ('BRK', 'Brooklyn'),
    ('QNS', 'Queens'),
    ('MAN', 'Manhattan'),
)

class PostAdForm(forms.ModelForm):  
    error_css_class = 'error'

    category = forms.ChoiceField(choices=CATEGORIES, required=True )
    location = forms.ChoiceField(choices=LOCATIONS, required=True )

    class Meta:
        model = PostAd

        widgets = {
            'name': forms.TextInput(attrs={'placeholder': 'What\'s your name?'}),
            'email': forms.TextInput(attrs={'placeholder': 'john@example.com'}),
            'gist': forms.TextInput(attrs={'placeholder': 'In a few words, I\'m looking for/to...'}),
            'expire': forms.TextInput(attrs={'placeholder': 'MM/DD/YYYY'})
        }

views.py

from django.http import HttpResponse  
from django.views.generic import FormView  
from .models import PostAd  
from .forms import PostAdForm

class PostAdPage(FormView):  
    template_name = 'post_ad.html'
    success_url = '/awesome/'
    form_class = PostAdForm

    def form_valid(self, form):
        return HttpResponse("Sweeeeeet.")

 templates/post_ad.html

{% extends 'base.html' %}  
{% comment %}

This is the display for the 'Post Ad' form.

URL: postad/  
Model: PostAd  
ModelForm: PostAdForm  
View: PostAdPage [FormView]  
View Return: HttpResponse : message - "Sweeeeeeeet."

* = preset when user is logged in.

{% endcomment %}

{% block content %}
<form action="/postad/" method="post">{% csrf_token %}
    <!-- *name -->
    {{  form.non_field_errors }}
    <div class="fieldWrapper">
        {{ form.name.errors }}
        <label for="id_name">Name</label>
        {{ form.name }}
    </div>
    <!-- *email -->
    <div class="fieldWrapper">
        {{ form.email.errors }}
        <label for="id_email">Email</label>
        {{ form.email }}
    </div>
    <!-- gist -->
    <div class="fieldWrapper">
        {{ form.gist.errors }}
        <label for="id_gist">Gist</label>
        {{ form.gist }}
    </div>
    <!-- category -->
    <div class="fieldWrapper">
        {{ form.category.errors }}
        <label for="id_category">Category</label>
        {{ form.category }}
    </div>
    <!-- location -->
    <div class="fieldWrapper">
        {{ form.location.errors }}
        <label for="id_name">Location</label>
        {{ form.location }}
    </div>
    <!-- description -->
    <div class="fieldWrapper">
        {{ form.description.errors }}
        <label for="id_description">Description</label>
        {{ form.description }}
    </div>
    <!-- expire -->
    <div class="fieldWrapper">
        {{ form.expire.errors }}
        <label for="id_expire">Expire</label>
        {{ form.expire }}
    </div>
    <button type="submit">
        <i class="fa fa-thumb-tack"></i> Post
    </button>
</form>
{% endblock %}

urls.py

from django.conf.urls import patterns, include, url  
from ads.views import PostAdPage

urlpatterns = patterns('',  
    url(r'^postad/', PostAdPage.as_view()),
)

That's about it. It works. I'm sure I'll post much more on ChoiceFields eventually.

I love you, Renee. Let's go. In everything I do.

 

 

Greg

Software Engineer

Subscribe to GregBlogs