Django Class-BasedViews CoMo Rich Web, October 2010
Agenda • Python 101 • RegularViews • GenericViews • Class-BasedViews
Python 101
# defining a function def say_hello(subject): print 'Hello, %s' % subject # calling a function say_hello('World')
# defining a function def say_hello(subject): print 'Hello, %s' % subject # calling a function say_hello('World') # defining a class class HelloSayer(object): def __init__(self, name): self.name = name def say_hello(self): print 'Hello, %s' % self.name # creating an object instance i = HelloSayer('World') i.say_hello()
First-Class Everything • first-class functions • can be stored in variables • can be passed into other functions • can be returned from functions • first-class classes • ditto all the above
f = say_hello f('Everybody') cls = MyClass j = cls('Everybody') j.say_hello() Text
class FakeFunction(object): def __init__(self): print 'Constructing...' def __call__(self): print 'You called?' f = FakeFunction() # Constructing... f() # You called?
result = x() # is `x()` calling a function? # creating an object? # or calling a method on an object?
DjangoViews
• a view is a function that takes (at minimum) an HttpRequest and returns an HttpResponse • views usually live in the file views.py • URLs are routed to views using patterns in the file urls.py View Basics
# __init__.py intentionally left blank # models.py intentionally left blank # views.py from django.http import HttpResponse def homepage(request): return HttpResponse('<html><body><h1>Welcome to website</h1></body></html>') # urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^$', 'myapp.views.homepage'), )
# views.py def user_profile(request, username): # do useful stuff here... return HttpResponse('''<html><body> <h1>Profile for user %s</h1> </body></html>''' % username) # urls.py urlpatterns = patterns('', (r'^user/(w+)/profile$', 'myapp.views.user_profile'), )
GenericViews
Paving the Cow Paths • “CRUD” apps have well-known patterns • dynamic typing allows Django to provide common view patterns as reusable functions
# hypothetical URL: /users?page=3 def user_list(request): page = int(request.GET.get('page', '1')) # sloppy parsing users = User.objects.all() per_page = 20 num_pages = math.ceil(len(users) / per_page) # buggy math if page <= 0 or page > num_pages: raise Http404() start_index = (page - 1) * per_page # buggy math end_index = page * per_page # buggy math users_on_page = users[start_index:end_index] context = { 'users': users_on_page, 'page': page, 'num_pages': num_pages # next or prev pages? } return render_to_response('myapp/user_list.html', context)
from django.views.generic import list_detail # hypothetical URL: /users?page=3 def user_list(request): return list_detail.object_list(request, queryset=User.objects.all(), paginate_by=20)
from django.views.generic import list_detail # hypothetical URL: /users?staff=y def user_list(request): if request.GET.get('staff', 'n').lower() == 'y': qs = Users.objects.filter(staff=True) else: qs = Users.objects.all() return list_detail.object_list(request, queryset=qs, paginate_by=20)
Going off the Beaten Path • at some point you’ll want to customize the generic views even more • wrapping only gets you so far • what about deeper behavior changes? • e.g,“delete” should actually flag as “inactive”
Class-BasedViews
Benefits • control not just parameters but behavior • more code reuse
# completely made-up example from django.views.generic.list_detail import ObjectListView class UserListView(ObjectListView): def get_queryset(self): if self.request.GET.get('staff', 'n').lower() == 'y': return Users.objects.filter(staff=True) else: return Users.objects.all() # meanwhile, in urls.py... (r'^users$', 'myapp.views.UserListView')
# completely made-up example from django.views.generic.create_update import DeleteObjectView class DeleteUserView(DeleteObjectView): def perform_deletion(self, user): user.is_active = False user.save()
Not a Silver Bullet • still only allows customization the original author thought of • can introduce multithreading issues • “official” Django views aren’t finished yet
Questions? Thanks for listening!

Django class based views

  • 1.
  • 2.
    Agenda • Python 101 •RegularViews • GenericViews • Class-BasedViews
  • 3.
  • 4.
    # defining afunction def say_hello(subject): print 'Hello, %s' % subject # calling a function say_hello('World')
  • 5.
    # defining afunction def say_hello(subject): print 'Hello, %s' % subject # calling a function say_hello('World') # defining a class class HelloSayer(object): def __init__(self, name): self.name = name def say_hello(self): print 'Hello, %s' % self.name # creating an object instance i = HelloSayer('World') i.say_hello()
  • 6.
    First-Class Everything • first-classfunctions • can be stored in variables • can be passed into other functions • can be returned from functions • first-class classes • ditto all the above
  • 7.
    f = say_hello f('Everybody') cls= MyClass j = cls('Everybody') j.say_hello() Text
  • 8.
    class FakeFunction(object): def __init__(self): print'Constructing...' def __call__(self): print 'You called?' f = FakeFunction() # Constructing... f() # You called?
  • 9.
    result = x() #is `x()` calling a function? # creating an object? # or calling a method on an object?
  • 10.
  • 11.
    • a viewis a function that takes (at minimum) an HttpRequest and returns an HttpResponse • views usually live in the file views.py • URLs are routed to views using patterns in the file urls.py View Basics
  • 12.
    # __init__.py intentionallyleft blank # models.py intentionally left blank # views.py from django.http import HttpResponse def homepage(request): return HttpResponse('<html><body><h1>Welcome to website</h1></body></html>') # urls.py from django.conf.urls.defaults import * urlpatterns = patterns('', (r'^$', 'myapp.views.homepage'), )
  • 13.
    # views.py def user_profile(request,username): # do useful stuff here... return HttpResponse('''<html><body> <h1>Profile for user %s</h1> </body></html>''' % username) # urls.py urlpatterns = patterns('', (r'^user/(w+)/profile$', 'myapp.views.user_profile'), )
  • 14.
  • 15.
    Paving the CowPaths • “CRUD” apps have well-known patterns • dynamic typing allows Django to provide common view patterns as reusable functions
  • 16.
    # hypothetical URL:/users?page=3 def user_list(request): page = int(request.GET.get('page', '1')) # sloppy parsing users = User.objects.all() per_page = 20 num_pages = math.ceil(len(users) / per_page) # buggy math if page <= 0 or page > num_pages: raise Http404() start_index = (page - 1) * per_page # buggy math end_index = page * per_page # buggy math users_on_page = users[start_index:end_index] context = { 'users': users_on_page, 'page': page, 'num_pages': num_pages # next or prev pages? } return render_to_response('myapp/user_list.html', context)
  • 17.
    from django.views.generic importlist_detail # hypothetical URL: /users?page=3 def user_list(request): return list_detail.object_list(request, queryset=User.objects.all(), paginate_by=20)
  • 18.
    from django.views.generic importlist_detail # hypothetical URL: /users?staff=y def user_list(request): if request.GET.get('staff', 'n').lower() == 'y': qs = Users.objects.filter(staff=True) else: qs = Users.objects.all() return list_detail.object_list(request, queryset=qs, paginate_by=20)
  • 19.
    Going off theBeaten Path • at some point you’ll want to customize the generic views even more • wrapping only gets you so far • what about deeper behavior changes? • e.g,“delete” should actually flag as “inactive”
  • 20.
  • 21.
    Benefits • control notjust parameters but behavior • more code reuse
  • 22.
    # completely made-upexample from django.views.generic.list_detail import ObjectListView class UserListView(ObjectListView): def get_queryset(self): if self.request.GET.get('staff', 'n').lower() == 'y': return Users.objects.filter(staff=True) else: return Users.objects.all() # meanwhile, in urls.py... (r'^users$', 'myapp.views.UserListView')
  • 23.
    # completely made-upexample from django.views.generic.create_update import DeleteObjectView class DeleteUserView(DeleteObjectView): def perform_deletion(self, user): user.is_active = False user.save()
  • 24.
    Not a SilverBullet • still only allows customization the original author thought of • can introduce multithreading issues • “official” Django views aren’t finished yet
  • 25.