Django : building a Python web app

INTRODUCTION

  • Presentations
    • Davin Baragiotta
    • Montréal-Python (MP, sprints/hackathons, workshops, PyCon)
    • Sponsors
  • Objectives
    • know the architecture of a project : main files
    • manage data in the admin backend
    • present data in the frontend
  • Documentation
    • doc : good version of Django
    • tutorial
      • Part 1 : create a project, create an app, play with ORM (API)
        covered here
      • Part 2 : backend (admin)
        covered here
      • Part 3 : frontend
        covered here, even more straightforward ;)_
      • Part 4 : forms and generic views
        not covered here
  • Technical setup
    >>> import django
    >>> django.get_version()
    '1.4'
    >>> import south
    >>> south.__version__
    '0.7.4.'
    
    • Python >= 2.5
    • Django 1.4
      • Mac OS X : see tutorial Part 1 for extra config
    • South 0.7.4 (optional)

PART 1 : WEB DEVELOPMENT WITH DJANGO : ARCHITECTURE OF A PROJECT

Web development

  • schema : web development
    • web framework's role : help to build a response to a request
  • environments
    • development (DEV)
    • deployment (TEST, PROD)

Django

Why Django vs other framework (e.g.: CherryPy, Pyramid, web2py)
  • all-in-one
  • admin : best-seller ;)
  • docs
  • community : widespread use
Main files
  • urls.py
  • views.py
  • models.py
  • templates (HTML)
  • admin.py

Project : requirements

Montréal-Python has a rugby league (not true : DoesNotExist).
They contact you for a website that could manage the players and the teams...
... as well as plan the matches for the season.

Project : modeling

  • Team
  • Player
  • Season
  • Match

PART 2 : HANDS-ON : PROJECT AND APPLICATIONS

Creating a project

django-admin.py startproject mp_rugby_league
cd mp_rugby_league

Giving the full path to the django-admin.py script might be necessary on some OS. E.g. Windows

  • overview of the generated files
python manage.py runserver
  • settings.py
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
            'NAME': 'mp_rugby_league.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.
        }
    }
    

Creating an application

python manage.py startapp teams
  • overview of the generated files
  • settings.py
    INSTALLED_APPS = (
        # ...
        'teams',
    )
    

South

  • settings.py
    INSTALLED_APPS = (
        # ...
        'south',
    )
    
  • creating migration for a new app
    python manage.py schemamigration teams --initial
    
    • creating migration for an existing app (not the case here)
      python manage.py schemamigration --auto
      
  • creating south's tables
    python manage.py syncdb
    
  • applying migrations
    python manage.py migrate teams
    

Backend : managing data in the admin

  • urls.py
    activate admin : uncomment
    # ...
    
    from django.contrib import admin
    admin.autodiscover()
    
    urlpatterns = patterns('',
        # ...
        url(r'^admin/', include(admin.site.urls)),
    )
    
  • settings.py
    INSTALLED_APPS = (
        # ...
        'django.contrib.admin',
        # ...
    )
    
  • creating admin's tables
    python manage.py syncdb
    
  • teams/models.py
    def __unicode__(self):
        return ""  # code here the desired unicode string to be returned
    
    • Player.firstname

If south installed, create and apply migration :

python manage.py schemamigration teams --auto
python manage.py migrate teams

Otherwise :

  • delete mp_rugby_league.db
python manage.py syncdb
  • teams/models.py
    • adding a relation between Player and Team :
      • Player.team
    • modify database accordingly :
      • south : create and apply migration
      • else : delete db and syncdb
  • add some Teams and Players (objects) in the admin

Frontend : presenting data

  • views.py
    passing a variable to the template
  • templates/home.html
    using a variable in the template :
    {{ var }}
    
  • views.py
    place to code the logic, in Python...
    ... easier if you explore interactively what you can code.

    python manage.py shell
    
  • ORM (API) : object relation mapping
    from teams.models import *
    teams = Team.objects.all()
    for t in teams: print t
    t = teams[0]
    t.player_set.all()
    p = Player.objects.get(id=1)
    p.id
    p = Player.objects.get(id=314)
    t.id
    players = Player.objects.filter(team__name__startswith='Pyth')
    
  • teams/models.py
    related_name = "players" 
    
  • restart the shell
    t.players.all()
    t.players.count()
    
  • views.py
    passing the relevant variables for the home page
    after playing with the ORM in the shell.
  • templates/home.html
    for loop in templates :
    {% for t in teams %}
    {% endfor %}
    

PART 3 : PIMPED MPRL PROJECT

Template inheritance

  • base.html
    {% block main %}
    {% endblock %}
    
  • templates
    {% extends "base.html" %}
    
    {% block main %}
    {% endblock %}
    

URL with parameters

  • detail pages : receiving the object's id
    • urls.py : import of teams app's urls
      urlpatterns = patterns('',
          # ...
          url(r'^', include('teams.urls')),
      )
      
  • teams/urls.py
    urlpatterns = patterns('teams.views',
        url(r'^teams/(?P<id>\d+)$', 'team_detail', name="team"),
    )
    
  • teams/views.py
    from django.shortcuts import render
    
    from teams.models import Team
    
    def team_detail(request, id):
        team = Team.objects.get(id=id)
        c = {
            'team': team,
        }
        return render(request, "teams/team_detail.html", c)
    
  • templates/teams/team_detail.html
    {{ team.name }}
    

Pimped Admin : ModelAdmin

https://docs.djangoproject.com/en/1.4/ref/contrib/admin/

  • teams/admin.py
  • classes TeamAdmin, PlayerAdmin
    inherit of ModelAdmin
    class TeamAdmin(admin.ModelAdmin):
        pass
    
    class PlayerAdmin(admin.ModelAdmin):
        pass
    
  • register Model with ModelAdmin
    admin.site.register(Team, TeamAdmin)
    admin.site.register(Player, PlayerAdmin)
    
  • config ModelAdmin
    list_display
    search_fields
    list_filter
    

Jump in time : download source

  • Extract
  • Pimped? What's new?

Static files : CSS, images and js

https://docs.djangoproject.com/en/1.4/howto/static-files/

  • directory : static
    • css
    • images
    • js
  • settings.py
    PROJECT_ROOT = os.path.dirname(__file__)
    SITE_ROOT = os.path.dirname(PROJECT_ROOT)
    
    MEDIA_ROOT = os.path.join(PROJECT_ROOT, 'media')
    MEDIA_URL = '/media/'
    
    STATIC_ROOT = os.path.join(SITE_ROOT, 'site_static')
    STATIC_URL = '/static/'
    STATICFILES_DIRS = (
        os.path.join(PROJECT_ROOT, 'static'),
    )
    
  • urls.py
    from django.contrib.staticfiles.urls import staticfiles_urlpatterns
    
    # ...
    
    urlpatterns += staticfiles_urlpatterns()
    
  • templates
    {{ STATIC_URL }}
    

Pimped templates

  • templates/base.html

User connexion

  • templates
    • connexion.html
    • deconnexion.html
  • urls.py
    urlpatterns = patterns('',
        # ...
        url(r'^login/$', 'django.contrib.auth.views.login', 
            dict(template_name='connexion.html',), 
            'connexion'
        ),
        url(r'^logout/$', 'django.contrib.auth.views.logout', 
            dict(template_name='deconnexion.html',), 
            'deconnexion'
        ),
        # ...
    )
    
  • settings.py
    LOGIN_URL = "/login/" 
    LOGIN_REDIRECT_URL = "/" 
    

PART 4 : HANDS-ON : CREATING THE SEASON APP FOR THE MPRL PROJECT

Create a season app

Add a Match model in this new app

  • Match
    • date
    • place
    • team1
    • team2
    • score1
    • score2

Other exercise : age of a player

  • Player.birth_date
  • Player.age()
    add a age() method on the Player class using the birth date.

CONCLUSION : CONTINUING ON

  • Channel IRC #django :
    irc://irc.freenode.net/django
  • Enjoy!

SATISFACTION SURVEY