Django Heresies

Simon Willison
Simon WillisonCEO and Co-Founder at Lanyrd
Django Heresies

Simon Willison                  @simonw
EuroDjangoCon     http://simonwillison.net/
4th May 2009
http://www.flickr.com/photos/ianlloyd/264753656/
DJANGO IS AWESOME
Selling bacon on the internet
Pulitzer prize winning journalism
Saving children’s lives in Kenya
Heresy
“An opinion at variance with the
orthodox or accepted doctrine”
Templates
{% if %} tags SUCK
{% if %} tags SUCK
•   Every time you {% endifnotequal %},
    God kicks the Django Pony
{% if %} tags SUCK
•   Every time you {% endifnotequal %},
    God kicks the Django Pony
http://docs.djangoproject.com/en/dev/misc/design-philosophies/




“   Don’t invent a programming language
    The template system intentionally doesn’t allow the
    following:

    
 •
 Assignment to variables
    
 •
 Advanced logic
    The goal is not to invent a programming language.
    The goal is to offer just enough programming-esque
    functionality, such as branching and looping, that is


                                                          ”
    essential for making presentation-related decisions.
Django Heresies
Django Heresies
{% if photo.width > 390 %}
...
{% endif %}
http://www.djangosnippets.org/snippets/1350/
               Chris Beaven (aka SmileyChris)


'''
A smarter {% if %} tag for django templates.

While retaining current Django functionality, it also
handles equality, greater than and less than operators.
Some common case examples::

      {% if articles|length >= 5 %}...{% endif %}
      {% if quot;ifnotequal tagquot; != quot;beautifulquot; %}...{% endif %}
'''



{% load smartif %} replaces the Django {% if %} tag
http://www.djangosnippets.org/snippets/1350/
               Chris Beaven (aka SmileyChris)


'''
A smarter {% if %} tag for django templates.

While retaining current Django functionality, it also
handles equality, greater than and less than operators.
Some common case examples::

      {% if articles|length >= 5 %}...{% endif %}
      {% if quot;ifnotequal tagquot; != quot;beautifulquot; %}...{% endif %}
'''



{% load smartif %} replaces the Django {% if %} tag
Silencing errors
•   2003: “template authors shouldn’t be able to
    break the site”

•   2008: “I can't think of a single time this
    feature has helped me, and plenty of
    examples of times that it has tripped me up.”

•   Silent {{ foo.bar }} is OK, silent tags are evil

•   django-developers: http://bit.ly/silentfail
Project layout
      http://www.flickr.com/photos/macrorain/2789698166/
Relocatable
TEMPLATE_DIRS = (
    # Don't forget to use absolute paths,
    # not relative paths.
)

import os
OUR_ROOT = os.path.realpath(
  os.path.dirname(__file__)
)
...
TEMPLATE_DIRS = os.path.join(OUR_ROOT, 'templates')
Relocatable
TEMPLATE_DIRS = (
    # Don't forget to use absolute paths,
    # not relative paths.
)

import os
OUR_ROOT = os.path.realpath(
  os.path.dirname(__file__)
)
...
TEMPLATE_DIRS = os.path.join(OUR_ROOT, 'templates')
local_settings.py

•   svn:ignore local_settings.py ?
    •   Can’t easily test your production settings
    •   Configuration isn’t in source control!
Environments

zoo/configs/common_settings.py

zoo/configs/alpha/app.wsgi
zoo/configs/alpha/manage.py
zoo/configs/alpha/settings.py

zoo/configs/testing/app.wsgi
zoo/configs/testing/manage.py
zoo/configs/testing/settings.py
zoo/configs/alpha/settings.py

from zoo.configs.common_settings import *

DEBUG = True
TEMPLATE_DEBUG = DEBUG

# Database settings
DATABASE_NAME = 'zoo_alpha'
DATABASE_USER = 'zoo_alpha'
Reusable code
        http://www.flickr.com/photos/ste3ve/521083510/
Django Heresies
Generic views
def object_detail(request, queryset, object_id=None,
        slug=None, slug_field='slug',
        template_name=None, template_name_field=None,
        template_loader=loader, extra_context=None,
        context_processors=None,
        template_object_name='object', mimetype=None
     ):
object_detail drawbacks
 •   You can’t swap the ORM for something else
     (without duck typing your own queryset)
 •   You have to use RequestContext
 •   You can’t modify something added to the
     context; you can only specify extra_context
 •   That’s despite a great deal of effort going in
     to making the behaviour customisable
newforms-admin

•   De-coupled admin from the rest of Django
•   A new approach to customisation
•   Powerful subclassing pattern
Fine grained permissions
class Entry(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey('auth.User')

class EntryAdmin(admin.ModelAdmin):
    exclude = ('author',)
    def queryset(self, request):
        queryset = super(EntryAdmin, self).queryset(request)
        return queryset.filter(author = request.user)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
    def has_change_permission(self, request, axj=None):
        if not obj:
            return True # access to change list
        return obj.author == request.user
    has_delete_permission = has_change_permission

admin.site.register(Entry, EntryAdmin)
Fine grained permissions
class Entry(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey('auth.User')

class EntryAdmin(admin.ModelAdmin):
    exclude = ('author',)
    def queryset(self, request):
        queryset = super(EntryAdmin, self).queryset(request)
        return queryset.filter(author = request.user)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
    def has_change_permission(self, request, obj=None):
        if not obj:
            return True # access to change list
        return obj.author == request.user
    has_delete_permission = has_change_permission

admin.site.register(Entry, EntryAdmin)
Fine grained permissions
class Entry(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey('auth.User')

class EntryAdmin(admin.ModelAdmin):
    exclude = ('author',)
    def queryset(self, request):
        queryset = super(EntryAdmin, self).queryset(request)
        return queryset.filter(author = request.user)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
    def has_change_permission(self, request, obj=None):
        if not obj:
            return True # access to change list
        return obj.author == request.user
    has_delete_permission = has_change_permission

admin.site.register(Entry, EntryAdmin)
Fine grained permissions
class Entry(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey('auth.User')

class EntryAdmin(admin.ModelAdmin):
    exclude = ('author',)
    def queryset(self, request):
        queryset = super(EntryAdmin, self).queryset(request)
        return queryset.filter(author = request.user)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
    def has_change_permission(self, request, obj=None):
        if not obj:
            return True # access to change list
        return obj.author == request.user
    has_delete_permission = has_change_permission

admin.site.register(Entry, EntryAdmin)
Fine grained permissions
class Entry(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey('auth.User')

class EntryAdmin(admin.ModelAdmin):
    exclude = ('author',)
    def queryset(self, request):
        queryset = super(EntryAdmin, self).queryset(request)
        return queryset.filter(author = request.user)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
    def has_change_permission(self, request, obj=None):
        if not obj:
            return True # access to change list
        return obj.author == request.user
    has_delete_permission = has_change_permission

admin.site.register(Entry, EntryAdmin)
Fine grained permissions
class Entry(models.Model):
    title = models.CharField(max_length=255)
    author = models.ForeignKey('auth.User')

class EntryAdmin(admin.ModelAdmin):
    exclude = ('author',)
    def queryset(self, request):
        queryset = super(EntryAdmin, self).queryset(request)
        return queryset.filter(author = request.user)
    def save_model(self, request, obj, form, change):
        obj.author = request.user
        obj.save()
    def has_change_permission(self, request, obj=None):
        if not obj:
            return True # access to change list
        return obj.author == request.user
    has_delete_permission = has_change_permission

admin.site.register(Entry, EntryAdmin)
Objects can be views
•   A Django view is a function that takes a
    request object and returns a response
    object
    A Django view is a callable that takes a
    request object and returns a response
    object
Objects can be views
•   A Django view is a function that takes a
    request object and returns a response
    object
•   A Django view is a callable that takes a
    request object and returns a response
    object
    •   Just define __call__() on the class
Example: restview.py
 Django Snippets: http://bit.ly/restview
class ArticleView(RestView):

  def GET(request, article_id):
    return render(quot;article.htmlquot;, {
       'article': get_object_or_404(
         Article, pk = article_id),
    })

  def POST(request, article_id):
    form = ...
    return HttpResponseRedirect(request.path)
from django.http import HttpResponse

class RestView(object):

    def __call__(self, request, *args, **kwargs):
        if not hasattr(self, method):
            return self.method_not_allowed(method)
        return getattr(self, method)(request, *args, **kwargs)

    def method_not_allowed(self, method):
        response = HttpResponse('Not allowed: %s' % method)
        response.status_code = 405
        return response
django_openid

 •   Next generation of my django-openid project
 •   Taken a lot longer than I expected
 •   Extensive use of class-based customisation



GitHub: http://github.com/simonw/django-openid
consumer.py           Consumer




            LoginConsumer




   CookieConsumer     SessionConsumer




auth.py
              AuthConsumer




registration.py
           RegistrationConsumer
Suggestions from
          django_openid

•   Every decision should use a method
•   Every form should come from a method
•   Every model interaction should live in a method
•   Everything should go through a render() method
render()
class Consumer(object):
    ...
    base_template = 'django_openid/base.html'
    ...
    def render(self, request, template, context=None):
        context = context or {}
        context['base_template'] = self.base_template
        return TemplateResponse(
            request, template, context
        )
    ...
render()
class Consumer(object):
    ...
    base_template = 'django_openid/base.html'
    ...
    def render(self, request, template, context=None):
        context = context or {}
        context['base_template'] = self.base_template
        return TemplateResponse(
            request, template, context
        )
    ...
render()
class Consumer(object):
    ...
    base_template = 'django_openid/base.html'
    ...
    def render(self, request, template, context=None):
        context = context or {}
        context['base_template'] = self.base_template
        return TemplateResponse(
            request, template, context
        )
    ...
TemplateResponse
class MyCustom(BaseView):

   def index(self):
       response = super(MyCustom, self).index()
       # response is a TemplateResponse
       response.context['counter'] += 1
       response.template = 'some/other/template.html'
       return response

# Two classes
SimpleTemplateResponse(template, context)
TemplateResponse(request, template, context)
TemplateResponse
•   Subclasses can re-use your logic and
    extend or modify your context
    •   So can middleware and unit tests
•   GZip Middleware writes to
    response.content, needs work arounds
•   Should HttpResponse be immutable?
Ticket #6735, scheduled for Django 1.2
Storing state on self in
a class-based generic
view is not thread safe
Storing state on self in
a class-based generic
view is not thread safe
Testing
Django Core
•   Excellent testing culture
•   Dubious “find... | grep... | xargs wc -l”:
    •   74k lines of code
    •   45k lines of tests
•   “No new code without tests”
•   Coverage = 54.4%, increasing over time
Django community?

•   ... not so good
    •   even though django.test.client is great
•   Many reusable apps lack tests
    •   need more psychology!
nose is more fun

•   nosetests --with-coverage
    •   (coming to a SoC project near you)
•   nosetests --pdb
•   nosetests --pdb-failures
Test views directly

•   Hooking up views to a URLconf just so
    you can test them is fiddly
    •   ... and sucks for reusable apps
•   A view function takes a request and
    returns a response
RequestFactory
rf = RequestFactory()

get_request = rf.get('/hello/')
post_request = rf.post('/submit/', {
   'foo': 'bar'
})
delete_request = rf.delete('/item/1/')


      http://bit.ly/requestfactory
The HttpRequest constructor
isn’t doing anything useful at
        the moment...
A web-based interface?
•   Testing would be more fun with pretty graphs
    •   ... and animated progress meters
    •   ... and a “test now” button
    •   ... maybe the Django pony could smile at
        you when your tests pass
•   Cheap continuous integration: run tests every
    time a file changes on disk?
settings.py is the root of all evil
Why did PHP magic_quotes suck?


•   They made it impossible to write reusable code
•   What if your code expects them to be on, but a
    library expects them to be off?
•   Check get_magic_quotes_gpc() and
    unescape... but what if some other library has
    done that first?
settings.py problems
•   Middleware applies globally, even to
    those applications that don’t want it
•   Anything fixed in settings.py I inevitably
    want to dynamically alter at runtime
    •   TEMPLATE_DIRS for mobile sites
    •   DB connections
•   How about per-application settings?
Grr
>>> from django import db
Traceback (most recent call last):
  File quot;<stdin>quot;, line 1, in <module>
  ...
ImportError: Settings cannot be imported,
because environment variable
DJANGO_SETTINGS_MODULE is undefined.
http://www.flickr.com/photos/raceytay/2977241805/




Turtles all the way down
“an infinite regression belief
 about cosmology and the
  nature of the universe”
The Django Contract
•   A view is a callable that takes a request object and
    returns a response object
The Django Contract
•   A view is a callable that takes a request object and
    returns a response object

•   Primary URLconf: selects a view based on regular
    expressions
The Django Contract
•   A view is a callable that takes a request object and
    returns a response object

•   Primary URLconf: selects a view based on regular
    expressions

•   Application: sometimes has its own URLconf include()d
    in to the primary
The Django Contract
•   A view is a callable that takes a request object and
    returns a response object

•   Primary URLconf: selects a view based on regular
    expressions

•   Application: sometimes has its own URLconf include()d
    in to the primary

•   Middleware: a sequence of globally applied classes
    process_request/process_response/process_exception
The Django Contract
•   A view is a callable that takes a request object and
    returns a response object

•   Primary URLconf: selects a view based on regular
    expressions

•   Application: sometimes has its own URLconf include()d
    in to the primary

•   Middleware: a sequence of globally applied classes
    process_request/process_response/process_exception

•   Site: a collection of applications + settings.py + urls.py
Extended Contract
•   A view is a callable that
    takes a request and returns a response

•   URLconf: a callable that
    takes a request and returns a response

•   Application: a callable that
    takes a request and returns a response

•   Middleware: a callable that
    takes a request and returns a response

•   Site: a callable that takes a request and returns a response
http://www.flickr.com/photos/enil/2440955556/




Let’s call them “turtles”
Three species of turtle

•   Django request / response
•   WSGI
•   HTTP


•   What if they were interchangeable?
Three species of turtle
•   Django request / response
•   WSGI
    •   Christopher Cahoon, SoC
    •   django_view_from_wsgi_app() http://bit.ly/djwsgi
    •   django_view_dec_from_wsgi_middleware()

•   HTTP
    •   paste.proxy
http://www.flickr.com/photos/remiprev/336851630/




Micro frameworks
http://github.com/
juno   782 lines
                       breily/juno
                   http://github.com/
newf   144 lines
                    JaredKuolt/newf
                  http://github.com/
mnml   205 lines
                 bradleywright/mnml
                   http://github.com/
itty   406 lines
                    toastdriven/itty
djng
   http://github.com/simonw/djng
(First commit at 5.47am this morning)
A micro framework
that depends on a
macro framework
class Router(object):
    quot;quot;quot;
    Convenient wrapper around Django's urlresolvers, allowing them to be used
    from normal application code.
                                         
    from django.conf.urls.defaults import url
    router = Router(
        url('^foo/$', lambda r: HttpResponse('foo'), name='foo'),
        url('^bar/$', lambda r: HttpResponse('bar'), name='bar')
    )
    request = RequestFactory().get('/bar/')
    print router(request)
    quot;quot;quot;
    def __init__(self, *urlpairs):
        self.urlpatterns = patterns('', *urlpairs)
        self.resolver = urlresolvers.RegexURLResolver(r'^/', self)
                                            
    def handle(self, request):
        path = request.path_info
        callback, callback_args, callback_kwargs = self.resolver.resolve(path)
        return callback(request, *callback_args, **callback_kwargs)
                                            
    def __call__(self, request):
        return self.handle(request)
Re-imagining the core
 Django APIs, minus
urls.py and settings.py
http://github.com/simonw/djangopeople.net
http://www.flickr.com/photos/morgantj/2639793944/




                                                   Thank you
1 of 83

Recommended

Advanced Django by
Advanced DjangoAdvanced Django
Advanced DjangoSimon Willison
55.4K views81 slides
Introduction To Django (Strange Loop 2011) by
Introduction To Django (Strange Loop 2011)Introduction To Django (Strange Loop 2011)
Introduction To Django (Strange Loop 2011)Jacob Kaplan-Moss
14.4K views139 slides
Maintainable JavaScript 2012 by
Maintainable JavaScript 2012Maintainable JavaScript 2012
Maintainable JavaScript 2012Nicholas Zakas
90.8K views85 slides
The Best (and Worst) of Django by
The Best (and Worst) of DjangoThe Best (and Worst) of Django
The Best (and Worst) of DjangoJacob Kaplan-Moss
35.6K views53 slides
jQuery Anti-Patterns for Performance & Compression by
jQuery Anti-Patterns for Performance & CompressionjQuery Anti-Patterns for Performance & Compression
jQuery Anti-Patterns for Performance & CompressionPaul Irish
25.2K views68 slides
Class-based views with Django by
Class-based views with DjangoClass-based views with Django
Class-based views with DjangoSimon Willison
2.7K views23 slides

More Related Content

What's hot

Django a whirlwind tour by
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tourBrad Montgomery
1.6K views61 slides
Django Rest Framework and React and Redux, Oh My! by
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Eric Palakovich Carr
9.3K views49 slides
Django - 次の一歩 gumiStudy#3 by
Django - 次の一歩 gumiStudy#3Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3makoto tsuyuki
2.6K views150 slides
The Django Web Application Framework 2 by
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2fishwarter
7.7K views38 slides
Django by
DjangoDjango
DjangoKangjin Jun
1.9K views43 slides
Building a Dynamic Website Using Django by
Building a Dynamic Website Using DjangoBuilding a Dynamic Website Using Django
Building a Dynamic Website Using DjangoNathan Eror
6.8K views49 slides

What's hot(20)

Django Rest Framework and React and Redux, Oh My! by Eric Palakovich Carr
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!
Django - 次の一歩 gumiStudy#3 by makoto tsuyuki
Django - 次の一歩 gumiStudy#3Django - 次の一歩 gumiStudy#3
Django - 次の一歩 gumiStudy#3
makoto tsuyuki2.6K views
The Django Web Application Framework 2 by fishwarter
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
fishwarter7.7K views
Building a Dynamic Website Using Django by Nathan Eror
Building a Dynamic Website Using DjangoBuilding a Dynamic Website Using Django
Building a Dynamic Website Using Django
Nathan Eror6.8K views
Create responsive websites with Django, REST and AngularJS by Hannes Hapke
Create responsive websites with Django, REST and AngularJSCreate responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJS
Hannes Hapke47.3K views
Working with the django admin by flywindy
Working with the django admin Working with the django admin
Working with the django admin
flywindy2.5K views
jQuery from the very beginning by Anis Ahmad
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginning
Anis Ahmad11.8K views
OSCON Google App Engine Codelab - July 2010 by ikailan
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010
ikailan7K views
Overlays, Accordions & Tabs, Oh My by Steve McMahon
Overlays, Accordions & Tabs, Oh MyOverlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh My
Steve McMahon1.5K views
A Little Backbone For Your App by Luca Mearelli
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
Luca Mearelli2.5K views
jQuery Loves Developers - Oredev 2009 by Remy Sharp
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009
Remy Sharp3.5K views
ActiveWeb: Chicago Java User Group Presentation by ipolevoy
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
ipolevoy2K views
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes by Nina Zakharenko
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 MinutesDjangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Djangocon 2014 - Django REST Framework - So Easy You Can Learn it in 25 Minutes
Nina Zakharenko4.8K views
A Dexterity Intro for Recovering Archetypes Addicts by David Glick
A Dexterity Intro for Recovering Archetypes AddictsA Dexterity Intro for Recovering Archetypes Addicts
A Dexterity Intro for Recovering Archetypes Addicts
David Glick3.1K views
And now you have two problems. Ruby regular expressions for fun and profit by... by Codemotion
And now you have two problems. Ruby regular expressions for fun and profit by...And now you have two problems. Ruby regular expressions for fun and profit by...
And now you have two problems. Ruby regular expressions for fun and profit by...
Codemotion989 views
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ by Leonardo Balter
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJRealize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
Leonardo Balter1.1K views

Viewers also liked

Django in the Real World by
Django in the Real WorldDjango in the Real World
Django in the Real WorldJacob Kaplan-Moss
85.1K views189 slides
12 tips on Django Best Practices by
12 tips on Django Best Practices12 tips on Django Best Practices
12 tips on Django Best PracticesDavid Arcos
50.8K views26 slides
Django Best Practices by
Django Best PracticesDjango Best Practices
Django Best PracticesAbdullah Çetin ÇAVDAR
25.2K views213 slides
Django Forms: Best Practices, Tips, Tricks by
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksShawn Rider
23.4K views18 slides
Getting Started With Django by
Getting Started With DjangoGetting Started With Django
Getting Started With Djangojeff_croft
5.7K views78 slides
Django로 배우는 쉽고 빠른 웹개발 study 자료 by
Django로 배우는 쉽고 빠른 웹개발 study 자료Django로 배우는 쉽고 빠른 웹개발 study 자료
Django로 배우는 쉽고 빠른 웹개발 study 자료Han Sung Kim
1.7K views27 slides

Viewers also liked(19)

12 tips on Django Best Practices by David Arcos
12 tips on Django Best Practices12 tips on Django Best Practices
12 tips on Django Best Practices
David Arcos50.8K views
Django Forms: Best Practices, Tips, Tricks by Shawn Rider
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, Tricks
Shawn Rider23.4K views
Getting Started With Django by jeff_croft
Getting Started With DjangoGetting Started With Django
Getting Started With Django
jeff_croft5.7K views
Django로 배우는 쉽고 빠른 웹개발 study 자료 by Han Sung Kim
Django로 배우는 쉽고 빠른 웹개발 study 자료Django로 배우는 쉽고 빠른 웹개발 study 자료
Django로 배우는 쉽고 빠른 웹개발 study 자료
Han Sung Kim1.7K views
Architecture at SimpleGeo: Staying Agile at Scale by Mike Malone
Architecture at SimpleGeo: Staying Agile at ScaleArchitecture at SimpleGeo: Staying Agile at Scale
Architecture at SimpleGeo: Staying Agile at Scale
Mike Malone15.5K views
Cassandra Summit 2010 Performance Tuning by driftx
Cassandra Summit 2010 Performance TuningCassandra Summit 2010 Performance Tuning
Cassandra Summit 2010 Performance Tuning
driftx4.2K views
The Web map stack on Django by Paul Smith
The Web map stack on DjangoThe Web map stack on Django
The Web map stack on Django
Paul Smith6.7K views
Django - Python MVC Framework by Bala Kumar
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC Framework
Bala Kumar27.9K views
Etsy Activity Feeds Architecture by Dan McKinley
Etsy Activity Feeds ArchitectureEtsy Activity Feeds Architecture
Etsy Activity Feeds Architecture
Dan McKinley112K views
Introduction To Django by Jay Graves
Introduction To DjangoIntroduction To Django
Introduction To Django
Jay Graves14.4K views
Web Development with Python and Django by Michael Pirnat
Web Development with Python and DjangoWeb Development with Python and Django
Web Development with Python and Django
Michael Pirnat188.7K views
Introduction to Redis by Dvir Volk
Introduction to RedisIntroduction to Redis
Introduction to Redis
Dvir Volk121K views
Scalability, Availability & Stability Patterns by Jonas Bonér
Scalability, Availability & Stability PatternsScalability, Availability & Stability Patterns
Scalability, Availability & Stability Patterns
Jonas Bonér515.9K views

Similar to Django Heresies

Django Vs Rails by
Django Vs RailsDjango Vs Rails
Django Vs RailsSérgio Santos
5.4K views45 slides
Django design-patterns by
Django design-patternsDjango design-patterns
Django design-patternsAgiliq Info Solutions India Pvt Ltd
4.5K views26 slides
Django Class-based views (Slovenian) by
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)Luka Zakrajšek
1.1K views26 slides
WordPress plugin #3 by
WordPress plugin #3WordPress plugin #3
WordPress plugin #3giwoolee
364 views68 slides
Django workshop : let's make a blog by
Django workshop : let's make a blogDjango workshop : let's make a blog
Django workshop : let's make a blogPierre Sudron
2.1K views40 slides
Тестирование и Django by
Тестирование и DjangoТестирование и Django
Тестирование и DjangoMoscowDjango
1.7K views42 slides

Similar to Django Heresies(20)

Django Class-based views (Slovenian) by Luka Zakrajšek
Django Class-based views (Slovenian)Django Class-based views (Slovenian)
Django Class-based views (Slovenian)
Luka Zakrajšek1.1K views
WordPress plugin #3 by giwoolee
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
giwoolee364 views
Django workshop : let's make a blog by Pierre Sudron
Django workshop : let's make a blogDjango workshop : let's make a blog
Django workshop : let's make a blog
Pierre Sudron2.1K views
Тестирование и Django by MoscowDjango
Тестирование и DjangoТестирование и Django
Тестирование и Django
MoscowDjango1.7K views
Django Pro ORM by Alex Gaynor
Django Pro ORMDjango Pro ORM
Django Pro ORM
Alex Gaynor3.1K views
Geek Moot '09 -- Smarty 101 by Ted Kulp
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
Ted Kulp2.2K views
Don't Repeat Yourself, Repeat Others by John Nunemaker
Don't Repeat Yourself, Repeat OthersDon't Repeat Yourself, Repeat Others
Don't Repeat Yourself, Repeat Others
John Nunemaker19.5K views
High Performance Django 1 by DjangoCon2008
High Performance Django 1High Performance Django 1
High Performance Django 1
DjangoCon20081.1K views
High Performance Django by DjangoCon2008
High Performance DjangoHigh Performance Django
High Performance Django
DjangoCon20081.3K views
Python magicmethods by dreampuf
Python magicmethodsPython magicmethods
Python magicmethods
dreampuf1.8K views
Advanced Python, Part 1 by Zaar Hai
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1
Zaar Hai776 views
Apostrophe (improved Paris edition) by tompunk
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)
tompunk3.3K views
Behind the curtain - How Django handles a request by Daniel Hepper
Behind the curtain - How Django handles a requestBehind the curtain - How Django handles a request
Behind the curtain - How Django handles a request
Daniel Hepper1.1K views
Gae Meets Django by fool2nd
Gae Meets DjangoGae Meets Django
Gae Meets Django
fool2nd1.5K views

More from Simon Willison

How Lanyrd does Geo by
How Lanyrd does GeoHow Lanyrd does Geo
How Lanyrd does GeoSimon Willison
5.7K views25 slides
Cheap tricks for startups by
Cheap tricks for startupsCheap tricks for startups
Cheap tricks for startupsSimon Willison
8.5K views26 slides
The Django Web Framework (EuroPython 2006) by
The Django Web Framework (EuroPython 2006)The Django Web Framework (EuroPython 2006)
The Django Web Framework (EuroPython 2006)Simon Willison
2.9K views56 slides
Building Lanyrd by
Building LanyrdBuilding Lanyrd
Building LanyrdSimon Willison
5.4K views65 slides
How we bootstrapped Lanyrd using Twitter's social graph by
How we bootstrapped Lanyrd using Twitter's social graphHow we bootstrapped Lanyrd using Twitter's social graph
How we bootstrapped Lanyrd using Twitter's social graphSimon Willison
2.2K views23 slides
Web Services for Fun and Profit by
Web Services for Fun and ProfitWeb Services for Fun and Profit
Web Services for Fun and ProfitSimon Willison
2.6K views95 slides

More from Simon Willison(20)

Cheap tricks for startups by Simon Willison
Cheap tricks for startupsCheap tricks for startups
Cheap tricks for startups
Simon Willison8.5K views
The Django Web Framework (EuroPython 2006) by Simon Willison
The Django Web Framework (EuroPython 2006)The Django Web Framework (EuroPython 2006)
The Django Web Framework (EuroPython 2006)
Simon Willison2.9K views
How we bootstrapped Lanyrd using Twitter's social graph by Simon Willison
How we bootstrapped Lanyrd using Twitter's social graphHow we bootstrapped Lanyrd using Twitter's social graph
How we bootstrapped Lanyrd using Twitter's social graph
Simon Willison2.2K views
Web Services for Fun and Profit by Simon Willison
Web Services for Fun and ProfitWeb Services for Fun and Profit
Web Services for Fun and Profit
Simon Willison2.6K views
Tricks & challenges developing a large Django application by Simon Willison
Tricks & challenges developing a large Django applicationTricks & challenges developing a large Django application
Tricks & challenges developing a large Django application
Simon Willison13.9K views
Advanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric by Simon Willison
Advanced Aspects of the Django Ecosystem: Haystack, Celery & FabricAdvanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric
Advanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric
Simon Willison26.2K views
Building Things Fast - and getting approval by Simon Willison
Building Things Fast - and getting approvalBuilding Things Fast - and getting approval
Building Things Fast - and getting approval
Simon Willison1.7K views
Rediscovering JavaScript: The Language Behind The Libraries by Simon Willison
Rediscovering JavaScript: The Language Behind The LibrariesRediscovering JavaScript: The Language Behind The Libraries
Rediscovering JavaScript: The Language Behind The Libraries
Simon Willison20.1K views
Building crowdsourcing applications by Simon Willison
Building crowdsourcing applicationsBuilding crowdsourcing applications
Building crowdsourcing applications
Simon Willison10.1K views
Evented I/O based web servers, explained using bunnies by Simon Willison
Evented I/O based web servers, explained using bunniesEvented I/O based web servers, explained using bunnies
Evented I/O based web servers, explained using bunnies
Simon Willison11.7K views
Cowboy development with Django by Simon Willison
Cowboy development with DjangoCowboy development with Django
Cowboy development with Django
Simon Willison16.9K views
Crowdsourcing with Django by Simon Willison
Crowdsourcing with DjangoCrowdsourcing with Django
Crowdsourcing with Django
Simon Willison12.4K views
Web App Security Horror Stories by Simon Willison
Web App Security Horror StoriesWeb App Security Horror Stories
Web App Security Horror Stories
Simon Willison13.1K views
Web Security Horror Stories by Simon Willison
Web Security Horror StoriesWeb Security Horror Stories
Web Security Horror Stories
Simon Willison32.1K views
When Ajax Attacks! Web application security fundamentals by Simon Willison
When Ajax Attacks! Web application security fundamentalsWhen Ajax Attacks! Web application security fundamentals
When Ajax Attacks! Web application security fundamentals
Simon Willison5.6K views

Recently uploaded

Vertical User Stories by
Vertical User StoriesVertical User Stories
Vertical User StoriesMoisés Armani Ramírez
14 views16 slides
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院 by
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院IttrainingIttraining
52 views8 slides
SAP Automation Using Bar Code and FIORI.pdf by
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdfVirendra Rai, PMP
23 views38 slides
Microsoft Power Platform.pptx by
Microsoft Power Platform.pptxMicrosoft Power Platform.pptx
Microsoft Power Platform.pptxUni Systems S.M.S.A.
53 views38 slides
The Research Portal of Catalonia: Growing more (information) & more (services) by
The Research Portal of Catalonia: Growing more (information) & more (services)The Research Portal of Catalonia: Growing more (information) & more (services)
The Research Portal of Catalonia: Growing more (information) & more (services)CSUC - Consorci de Serveis Universitaris de Catalunya
80 views25 slides
Info Session November 2023.pdf by
Info Session November 2023.pdfInfo Session November 2023.pdf
Info Session November 2023.pdfAleksandraKoprivica4
12 views15 slides

Recently uploaded(20)

【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院 by IttrainingIttraining
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
【USB韌體設計課程】精選講義節錄-USB的列舉過程_艾鍗學院
SAP Automation Using Bar Code and FIORI.pdf by Virendra Rai, PMP
SAP Automation Using Bar Code and FIORI.pdfSAP Automation Using Bar Code and FIORI.pdf
SAP Automation Using Bar Code and FIORI.pdf
6g - REPORT.pdf by Liveplex
6g - REPORT.pdf6g - REPORT.pdf
6g - REPORT.pdf
Liveplex10 views
Data Integrity for Banking and Financial Services by Precisely
Data Integrity for Banking and Financial ServicesData Integrity for Banking and Financial Services
Data Integrity for Banking and Financial Services
Precisely21 views
Case Study Copenhagen Energy and Business Central.pdf by Aitana
Case Study Copenhagen Energy and Business Central.pdfCase Study Copenhagen Energy and Business Central.pdf
Case Study Copenhagen Energy and Business Central.pdf
Aitana16 views
Business Analyst Series 2023 - Week 3 Session 5 by DianaGray10
Business Analyst Series 2023 -  Week 3 Session 5Business Analyst Series 2023 -  Week 3 Session 5
Business Analyst Series 2023 - Week 3 Session 5
DianaGray10248 views
Piloting & Scaling Successfully With Microsoft Viva by Richard Harbridge
Piloting & Scaling Successfully With Microsoft VivaPiloting & Scaling Successfully With Microsoft Viva
Piloting & Scaling Successfully With Microsoft Viva
Future of AR - Facebook Presentation by ssuserb54b561
Future of AR - Facebook PresentationFuture of AR - Facebook Presentation
Future of AR - Facebook Presentation
ssuserb54b56114 views
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive by Network Automation Forum
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLiveAutomating a World-Class Technology Conference; Behind the Scenes of CiscoLive
Automating a World-Class Technology Conference; Behind the Scenes of CiscoLive

Django Heresies

  • 1. Django Heresies Simon Willison @simonw EuroDjangoCon http://simonwillison.net/ 4th May 2009
  • 4. Selling bacon on the internet
  • 7. Heresy “An opinion at variance with the orthodox or accepted doctrine”
  • 9. {% if %} tags SUCK
  • 10. {% if %} tags SUCK • Every time you {% endifnotequal %}, God kicks the Django Pony
  • 11. {% if %} tags SUCK • Every time you {% endifnotequal %}, God kicks the Django Pony
  • 12. http://docs.djangoproject.com/en/dev/misc/design-philosophies/ “ Don’t invent a programming language The template system intentionally doesn’t allow the following: • Assignment to variables • Advanced logic The goal is not to invent a programming language. The goal is to offer just enough programming-esque functionality, such as branching and looping, that is ” essential for making presentation-related decisions.
  • 15. {% if photo.width > 390 %} ... {% endif %}
  • 16. http://www.djangosnippets.org/snippets/1350/ Chris Beaven (aka SmileyChris) ''' A smarter {% if %} tag for django templates. While retaining current Django functionality, it also handles equality, greater than and less than operators. Some common case examples:: {% if articles|length >= 5 %}...{% endif %} {% if quot;ifnotequal tagquot; != quot;beautifulquot; %}...{% endif %} ''' {% load smartif %} replaces the Django {% if %} tag
  • 17. http://www.djangosnippets.org/snippets/1350/ Chris Beaven (aka SmileyChris) ''' A smarter {% if %} tag for django templates. While retaining current Django functionality, it also handles equality, greater than and less than operators. Some common case examples:: {% if articles|length >= 5 %}...{% endif %} {% if quot;ifnotequal tagquot; != quot;beautifulquot; %}...{% endif %} ''' {% load smartif %} replaces the Django {% if %} tag
  • 19. 2003: “template authors shouldn’t be able to break the site” • 2008: “I can't think of a single time this feature has helped me, and plenty of examples of times that it has tripped me up.” • Silent {{ foo.bar }} is OK, silent tags are evil • django-developers: http://bit.ly/silentfail
  • 20. Project layout http://www.flickr.com/photos/macrorain/2789698166/
  • 21. Relocatable TEMPLATE_DIRS = ( # Don't forget to use absolute paths, # not relative paths. ) import os OUR_ROOT = os.path.realpath( os.path.dirname(__file__) ) ... TEMPLATE_DIRS = os.path.join(OUR_ROOT, 'templates')
  • 22. Relocatable TEMPLATE_DIRS = ( # Don't forget to use absolute paths, # not relative paths. ) import os OUR_ROOT = os.path.realpath( os.path.dirname(__file__) ) ... TEMPLATE_DIRS = os.path.join(OUR_ROOT, 'templates')
  • 23. local_settings.py • svn:ignore local_settings.py ? • Can’t easily test your production settings • Configuration isn’t in source control!
  • 25. zoo/configs/alpha/settings.py from zoo.configs.common_settings import * DEBUG = True TEMPLATE_DEBUG = DEBUG # Database settings DATABASE_NAME = 'zoo_alpha' DATABASE_USER = 'zoo_alpha'
  • 26. Reusable code http://www.flickr.com/photos/ste3ve/521083510/
  • 28. Generic views def object_detail(request, queryset, object_id=None, slug=None, slug_field='slug', template_name=None, template_name_field=None, template_loader=loader, extra_context=None, context_processors=None, template_object_name='object', mimetype=None ):
  • 29. object_detail drawbacks • You can’t swap the ORM for something else (without duck typing your own queryset) • You have to use RequestContext • You can’t modify something added to the context; you can only specify extra_context • That’s despite a great deal of effort going in to making the behaviour customisable
  • 30. newforms-admin • De-coupled admin from the rest of Django • A new approach to customisation • Powerful subclassing pattern
  • 31. Fine grained permissions class Entry(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin): exclude = ('author',) def queryset(self, request): queryset = super(EntryAdmin, self).queryset(request) return queryset.filter(author = request.user) def save_model(self, request, obj, form, change): obj.author = request.user obj.save() def has_change_permission(self, request, axj=None): if not obj: return True # access to change list return obj.author == request.user has_delete_permission = has_change_permission admin.site.register(Entry, EntryAdmin)
  • 32. Fine grained permissions class Entry(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin): exclude = ('author',) def queryset(self, request): queryset = super(EntryAdmin, self).queryset(request) return queryset.filter(author = request.user) def save_model(self, request, obj, form, change): obj.author = request.user obj.save() def has_change_permission(self, request, obj=None): if not obj: return True # access to change list return obj.author == request.user has_delete_permission = has_change_permission admin.site.register(Entry, EntryAdmin)
  • 33. Fine grained permissions class Entry(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin): exclude = ('author',) def queryset(self, request): queryset = super(EntryAdmin, self).queryset(request) return queryset.filter(author = request.user) def save_model(self, request, obj, form, change): obj.author = request.user obj.save() def has_change_permission(self, request, obj=None): if not obj: return True # access to change list return obj.author == request.user has_delete_permission = has_change_permission admin.site.register(Entry, EntryAdmin)
  • 34. Fine grained permissions class Entry(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin): exclude = ('author',) def queryset(self, request): queryset = super(EntryAdmin, self).queryset(request) return queryset.filter(author = request.user) def save_model(self, request, obj, form, change): obj.author = request.user obj.save() def has_change_permission(self, request, obj=None): if not obj: return True # access to change list return obj.author == request.user has_delete_permission = has_change_permission admin.site.register(Entry, EntryAdmin)
  • 35. Fine grained permissions class Entry(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin): exclude = ('author',) def queryset(self, request): queryset = super(EntryAdmin, self).queryset(request) return queryset.filter(author = request.user) def save_model(self, request, obj, form, change): obj.author = request.user obj.save() def has_change_permission(self, request, obj=None): if not obj: return True # access to change list return obj.author == request.user has_delete_permission = has_change_permission admin.site.register(Entry, EntryAdmin)
  • 36. Fine grained permissions class Entry(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey('auth.User') class EntryAdmin(admin.ModelAdmin): exclude = ('author',) def queryset(self, request): queryset = super(EntryAdmin, self).queryset(request) return queryset.filter(author = request.user) def save_model(self, request, obj, form, change): obj.author = request.user obj.save() def has_change_permission(self, request, obj=None): if not obj: return True # access to change list return obj.author == request.user has_delete_permission = has_change_permission admin.site.register(Entry, EntryAdmin)
  • 37. Objects can be views • A Django view is a function that takes a request object and returns a response object A Django view is a callable that takes a request object and returns a response object
  • 38. Objects can be views • A Django view is a function that takes a request object and returns a response object • A Django view is a callable that takes a request object and returns a response object • Just define __call__() on the class
  • 39. Example: restview.py Django Snippets: http://bit.ly/restview
  • 40. class ArticleView(RestView): def GET(request, article_id): return render(quot;article.htmlquot;, { 'article': get_object_or_404( Article, pk = article_id), }) def POST(request, article_id): form = ... return HttpResponseRedirect(request.path)
  • 41. from django.http import HttpResponse class RestView(object): def __call__(self, request, *args, **kwargs): if not hasattr(self, method): return self.method_not_allowed(method) return getattr(self, method)(request, *args, **kwargs) def method_not_allowed(self, method): response = HttpResponse('Not allowed: %s' % method) response.status_code = 405 return response
  • 42. django_openid • Next generation of my django-openid project • Taken a lot longer than I expected • Extensive use of class-based customisation GitHub: http://github.com/simonw/django-openid
  • 43. consumer.py Consumer LoginConsumer CookieConsumer SessionConsumer auth.py AuthConsumer registration.py RegistrationConsumer
  • 44. Suggestions from django_openid • Every decision should use a method • Every form should come from a method • Every model interaction should live in a method • Everything should go through a render() method
  • 45. render() class Consumer(object): ... base_template = 'django_openid/base.html' ... def render(self, request, template, context=None): context = context or {} context['base_template'] = self.base_template return TemplateResponse( request, template, context ) ...
  • 46. render() class Consumer(object): ... base_template = 'django_openid/base.html' ... def render(self, request, template, context=None): context = context or {} context['base_template'] = self.base_template return TemplateResponse( request, template, context ) ...
  • 47. render() class Consumer(object): ... base_template = 'django_openid/base.html' ... def render(self, request, template, context=None): context = context or {} context['base_template'] = self.base_template return TemplateResponse( request, template, context ) ...
  • 48. TemplateResponse class MyCustom(BaseView): def index(self): response = super(MyCustom, self).index() # response is a TemplateResponse response.context['counter'] += 1 response.template = 'some/other/template.html' return response # Two classes SimpleTemplateResponse(template, context) TemplateResponse(request, template, context)
  • 49. TemplateResponse • Subclasses can re-use your logic and extend or modify your context • So can middleware and unit tests • GZip Middleware writes to response.content, needs work arounds • Should HttpResponse be immutable?
  • 50. Ticket #6735, scheduled for Django 1.2
  • 51. Storing state on self in a class-based generic view is not thread safe
  • 52. Storing state on self in a class-based generic view is not thread safe
  • 54. Django Core • Excellent testing culture • Dubious “find... | grep... | xargs wc -l”: • 74k lines of code • 45k lines of tests • “No new code without tests” • Coverage = 54.4%, increasing over time
  • 55. Django community? • ... not so good • even though django.test.client is great • Many reusable apps lack tests • need more psychology!
  • 56. nose is more fun • nosetests --with-coverage • (coming to a SoC project near you) • nosetests --pdb • nosetests --pdb-failures
  • 57. Test views directly • Hooking up views to a URLconf just so you can test them is fiddly • ... and sucks for reusable apps • A view function takes a request and returns a response
  • 58. RequestFactory rf = RequestFactory() get_request = rf.get('/hello/') post_request = rf.post('/submit/', { 'foo': 'bar' }) delete_request = rf.delete('/item/1/') http://bit.ly/requestfactory
  • 59. The HttpRequest constructor isn’t doing anything useful at the moment...
  • 60. A web-based interface? • Testing would be more fun with pretty graphs • ... and animated progress meters • ... and a “test now” button • ... maybe the Django pony could smile at you when your tests pass • Cheap continuous integration: run tests every time a file changes on disk?
  • 61. settings.py is the root of all evil
  • 62. Why did PHP magic_quotes suck? • They made it impossible to write reusable code • What if your code expects them to be on, but a library expects them to be off? • Check get_magic_quotes_gpc() and unescape... but what if some other library has done that first?
  • 63. settings.py problems • Middleware applies globally, even to those applications that don’t want it • Anything fixed in settings.py I inevitably want to dynamically alter at runtime • TEMPLATE_DIRS for mobile sites • DB connections • How about per-application settings?
  • 64. Grr >>> from django import db Traceback (most recent call last): File quot;<stdin>quot;, line 1, in <module> ... ImportError: Settings cannot be imported, because environment variable DJANGO_SETTINGS_MODULE is undefined.
  • 66. “an infinite regression belief about cosmology and the nature of the universe”
  • 67. The Django Contract • A view is a callable that takes a request object and returns a response object
  • 68. The Django Contract • A view is a callable that takes a request object and returns a response object • Primary URLconf: selects a view based on regular expressions
  • 69. The Django Contract • A view is a callable that takes a request object and returns a response object • Primary URLconf: selects a view based on regular expressions • Application: sometimes has its own URLconf include()d in to the primary
  • 70. The Django Contract • A view is a callable that takes a request object and returns a response object • Primary URLconf: selects a view based on regular expressions • Application: sometimes has its own URLconf include()d in to the primary • Middleware: a sequence of globally applied classes process_request/process_response/process_exception
  • 71. The Django Contract • A view is a callable that takes a request object and returns a response object • Primary URLconf: selects a view based on regular expressions • Application: sometimes has its own URLconf include()d in to the primary • Middleware: a sequence of globally applied classes process_request/process_response/process_exception • Site: a collection of applications + settings.py + urls.py
  • 72. Extended Contract • A view is a callable that takes a request and returns a response • URLconf: a callable that takes a request and returns a response • Application: a callable that takes a request and returns a response • Middleware: a callable that takes a request and returns a response • Site: a callable that takes a request and returns a response
  • 74. Three species of turtle • Django request / response • WSGI • HTTP • What if they were interchangeable?
  • 75. Three species of turtle • Django request / response • WSGI • Christopher Cahoon, SoC • django_view_from_wsgi_app() http://bit.ly/djwsgi • django_view_dec_from_wsgi_middleware() • HTTP • paste.proxy
  • 77. http://github.com/ juno 782 lines breily/juno http://github.com/ newf 144 lines JaredKuolt/newf http://github.com/ mnml 205 lines bradleywright/mnml http://github.com/ itty 406 lines toastdriven/itty
  • 78. djng http://github.com/simonw/djng (First commit at 5.47am this morning)
  • 79. A micro framework that depends on a macro framework
  • 80. class Router(object):     quot;quot;quot; Convenient wrapper around Django's urlresolvers, allowing them to be used from normal application code.   from django.conf.urls.defaults import url router = Router( url('^foo/$', lambda r: HttpResponse('foo'), name='foo'), url('^bar/$', lambda r: HttpResponse('bar'), name='bar') ) request = RequestFactory().get('/bar/') print router(request) quot;quot;quot;     def __init__(self, *urlpairs):         self.urlpatterns = patterns('', *urlpairs)         self.resolver = urlresolvers.RegexURLResolver(r'^/', self)          def handle(self, request):         path = request.path_info         callback, callback_args, callback_kwargs = self.resolver.resolve(path)         return callback(request, *callback_args, **callback_kwargs)          def __call__(self, request):         return self.handle(request)
  • 81. Re-imagining the core Django APIs, minus urls.py and settings.py