An (HTML5) Form View

JQuery Mobile allows you to wrap a “regular” web site into a mobile web-site quickly. Once you have the site “mobile” you can begin to tweak and enhance it, but the first steps should be as fast as possible. This part of the tutorial will show you how to use (HTML5) forms with JQuery Mobile. There’s no requirement to use HTML5 with your forms, but many mobile web-browsers will automatically customise their input mechanisms with specialised keyboards when you do; that makes it much easier for users to enter data on a mobile platform.

This will be a fairly short tutorial; the point of the technology is to make the process simple. The jqm/form.html template is a short Django template which extends the jqm/simple.html template to allow for creating “just a form” templates very quickly from your existing forms.

You will likely want custom form-handling for your real applications, see the jqm/templates directory for the code to the jqm/form.html template.

HTML5 Forms

The django-html5 project provides support for using HTML5 widgets on a per-form basis. To install the module (if you didn’t during Django JQuery Mobile Setup:

$ pip install -e "git+"

once you have the module, you can customise your Django forms with html5.forms.widgets instances assigned to the widget parameter of your form fields. The only special case currently is for IntegerField, where you can use the html5.forms.fields.IntegerField class to provide min/max pass-through:

from django.utils.translation import ugettext_lazy as _
from django import forms
from html5.forms import fields as five_fields,widgets as five_widgets

class SampleForm( forms.Form ):
    """Sample form with HTML widgets"""
    number = five_fields.IntegerField(
        required = False,
        min_value = 0,
        max_value = 25,
        help_text = _('Some helpful text' ),
    range = forms.IntegerField(
        widget = five_widgets.RangeInput(
            attrs = dict(
                min = '0',
                max = '10',
    email = forms.CharField(
        widget = five_widgets.EmailInput(

Creating the View

We’ll create a view that pretends to allow the user to control their settings (actually controlling settings is just regular Django, and left to the reader). First we will register our new URL in

url(r'^/?$', 'tutorial.views.settings', name='settings'),

and a corresponding view function in our module:

from django.http import HttpResponse,HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.contrib import messages
import time

def settings( request ): request, _('A sample message %s')%(time.strftime('%H:%m:%S')) )
    if request.method == 'GET':
        form = SampleForm()
        form = SampleForm( request.POST )
        if not form.is_valid():
            messages.error( request, _("Unable to update"))
            messages.success( request, _("Updated"))
            return HttpResponseRedirect(
                reverse( 'home' )
    return render_to_response(
            'title': 'Settings Form',
            'form': form,
        context_instance = RC( request ),

from django.utils.translation import ugettext as _

The jqm/form.html template substitutes in our title and renders the form as the body of the page. It uses non-AJAX post to work around the JQuery Mobile redirect limitations. The Django messages framework is also used; it is rendered in the jqm/simple.html template as part of the page “header” (the bar at the top of the page).


When rendered on most mobile browsers (and most modern desktop browsers), your HTML5 inputs should have enhancements including customised input, basic data-validation and the like. The jqm/form.html template will render an unstyled “help” button for those fields which have help-text defined. Clicking the button will cause the help text to be displayed (again, in an unstyled manner).

_images/form5-1.png _images/form5-2.png

What’s with the Translations?

You may have noticed the strange pattern of importing _ at the top of the module and then again at the bottom of the module. This allows your definition-time (i.e. import-time) references to gettext (the translation entry point) to be to the lazy version, while your run-time references are to the non-lazy version without any special machinery required to have gettext find both.

Table Of Contents

Previous topic

Basic View (with Login/Logout)

This Page