Django Intro

Colin MacDonald

Web application framework

ORM

ORM Example classes

from django.db import models

class Person(models.Model):
    first = models.CharField(max_length=30)
    last = models.CharField(max_length=30)
    ...

class Employee(Person):
    alt_id = models.CharField(max_length=12, blank=True)
    ssn_last4 = models.CharField(max_length=4)
    md5_ssn = MD5Field()
    ...

class Dependent(Person):
    employee = models.ForeignKey(Employee)
    sequence_number = models.IntegerField(db_index=True)
    relation = models.CharField(max_length=30)

ORM Example Searches

Create new Employee & dependent
emp = Employee(first='John', last='Smith')
dep1 = Dependent(first='Jane', last='Smith', relation='spouse', employee=emp)
dep2 = Dependent(first='Steve', last='Smith', relation='child', employee=emp)
Fetch employee for dependent
dependent = Dependent.objects.get(first=some_value, last=some_value)
employee = dependent.employee
Fetch dependents for employee
employee = Employee.objects.get(md5_ssn=some_value)
dependents = employee.dependent_set.all()

Dispatching

urls.py

urls.py (cont.)

views.py

Despite the name, this is really part of the Controller part of MVC. It builds data structures (models) which are used to populate a template (view). The first parameter to a view function is always the request object.

from django.shortcuts import render_to_response
from django.template import RequestContext

def claim_detail(request, claim_number):
    context = RequestContext(request)
    context['claim'] = Claim.objects.get(claim_number=claim_number)
    return render_to_response("myapp/claim_detail.html", context_instance=context)

You can have other key-value parameters.

def claim_detail(request, claim_number, template="myapp/claim_detail.html"):
    context = RequestContext(request)
    context['claim'] = Claim.objects.get(claim_number=claim_number)
    return render_to_response(template, context_instance=context)

Templating

Templating Example

my_page.html

<html>
  <head>
    <title>My Page</title>
    ... css, javascript, etc. ...
    {% block extra_header %}{% endblock %}
  </head>
  <body>
    {% block page_header %}
    <h1>Welcome to My Page</h1>
    {% endblock %}
  </body>
</html>

Templating Example (cont.)

my_other_page.html

{% extends "my_page.html" %}

{% block extra_header %}
  h1 { color: red; }
{% endblock %}

{% block page_header %}
    <h1>Welcome to My Other Page</h1>
{% endblock %}

forms.py

forms.py example

Base class in django.contrib.auth

class AuthenticationForm(forms.Form):
    username = forms.CharField(label="Username", max_length=30)
    password = forms.CharField(label="Password", widget=forms.PasswordInput)
    ...

Extension which adds Terms of Use checkbox

class LoginForm(django.contrib.auth.AuthenticationForm):
    accept_terms = forms.BooleanField(
        label=u'I have read and accept the Terms of Use.',
        error_messages = {'required': u'Terms of Use not accepted.'}
        )

Example of a character field validated against a regex

    last_name = forms.RegexField(
        regex=r"^ *[\w\-' ]+ *$",
        max_length=30,
        widget=forms.TextInput(attrs={'class':'required'}),
        label=u'Last Name')

forms.py example (cont.)

In views.py:

from django.contrib.auth import login

def my_login(request):
    if request.method == "POST":
        form = LoginForm(data=request.POST)
        if form.is_valid():
            login(request, form.get_user())
            return HttpResponseRedirect('/benefits')
    else:
        form = LoginForm(request, auto_id=True)
    return render_to_response('registration/login.html', { 'form': form },
        context_instance=RequestContext(request))

Forms example (cont.)

In the template file:

<form id="form" method="post" action="/accounts/login/">
    <dl>
        <dt><label for="username">{{ form.username.label }}</label></dt>
        <dd>{{ form.username }}</dd>
        <dt><label for="password">{{ form.password.label }}</label></dt>
        <dd>{{ form.password }}</dd>
    </dl>
    <p>{{ form.accept_terms }} <label for="accept_terms">
        I have read and accept the Terms of Use.</label></p>
    <input type="submit" class="submit" value="Login >" />
</form>

There are also shortcuts that generate the form HTML: {{form.as_p}}, {{form.as_ul}}, {{form.as_table}}

Applications and Projects

Separability

MVC Example

Extracted from The Django Book.

This shows how Django's various files interact.

  • urls.py defines mappings of URLs to view functions.
  • views.py defines handler functions that do the work of the application: They interact with data and pass it to templates for display.
  • models.py defines data classes.
  • Template files contain standard HTML, plus markup for data display.

MVC Example (cont.)

urls.py

from django.conf.urls.defaults import *
import views

urlpatterns = patterns(,
    (r'^latest/$', views.latest_books),
)

views.py

from django.shortcuts import render_to_response
from models import Book

def latest_books(request):
    book_list = Book.objects.order_by('-pub_date')[:10]
    return render_to_response('latest_books.html', {'book_list': book_list})

MVC Example (cont.)

models.py

from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=50)
    pub_date = models.DateField()

latest_books.html

 <html><head><title>Books</title></head>
 <body>
     <h1>Books</h1>
     <ul>
         {% for book in book_list %}
         <li>{{ book.name }}</li>
         {% endfor %}
     </ul>
 </body></html>

Review

  • Components:
    • ORM (models.py)
    • Dispatching (urls.py, views.py)
    • Templating (*.html)
    • Forms (forms.py)
  • Applications and Projects

Conclusion

  • Seems to be the leading Python framework, based on PyCon 2010 experience.
  • Nice separation of responsibilities
  • Cleanly extensible
  • Limited magic
  • Good documentation
  • Active user community
    • Local meetup group
    • PBS & NASA