SlideShare a Scribd company logo
1 of 83
Download to read offline
Django Heresies

Simon Willison                  @simonw
EuroDjangoCon     http://simonwillison.net/
4th May 2009
http://www.ļ¬‚ickr.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.
{% 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.ļ¬‚ickr.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
    ā€¢   Conļ¬guration 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/conļ¬gs/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.ļ¬‚ickr.com/photos/ste3ve/521083510/
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 deļ¬ne __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 ā€œļ¬nd... | 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 ļ¬ddly
    ā€¢   ... 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 ļ¬le 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 ļ¬rst?
settings.py problems
ā€¢   Middleware applies globally, even to
    those applications that donā€™t want it
ā€¢   Anything ļ¬xed 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.ļ¬‚ickr.com/photos/raceytay/2977241805/




Turtles all the way down
ā€œan inļ¬nite 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.ļ¬‚ickr.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.ļ¬‚ickr.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.ļ¬‚ickr.com/photos/morgantj/2639793944/




                                                   Thank you

More Related Content

What's hot

Django a whirlwind tour
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tourBrad Montgomery
Ā 
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 Rest Framework and React and Redux, Oh My!Eric Palakovich Carr
Ā 
Django - ꬔ恮äø€ę­© gumiStudy#3
Django - ꬔ恮äø€ę­© gumiStudy#3Django - ꬔ恮äø€ę­© gumiStudy#3
Django - ꬔ恮äø€ę­© gumiStudy#3makoto tsuyuki
Ā 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2fishwarter
Ā 
Building a Dynamic Website Using Django
Building a Dynamic Website Using DjangoBuilding a Dynamic Website Using Django
Building a Dynamic Website Using DjangoNathan Eror
Ā 
Create responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJSCreate responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJSHannes Hapke
Ā 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORMYaroslav Muravskyi
Ā 
Working with the django admin
Working with the django admin Working with the django admin
Working with the django admin flywindy
Ā 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginningAnis Ahmad
Ā 
jQuery in 15 minutes
jQuery in 15 minutesjQuery in 15 minutes
jQuery in 15 minutesSimon Willison
Ā 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010ikailan
Ā 
Overlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh MyOverlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh MySteve McMahon
Ā 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your AppLuca Mearelli
Ā 
jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009Remy Sharp
Ā 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentationipolevoy
Ā 
Djangocon 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 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 MinutesNina Zakharenko
Ā 
A Dexterity Intro for Recovering Archetypes Addicts
A Dexterity Intro for Recovering Archetypes AddictsA Dexterity Intro for Recovering Archetypes Addicts
A Dexterity Intro for Recovering Archetypes AddictsDavid Glick
Ā 
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...
And now you have two problems. Ruby regular expressions for fun and profit by...Codemotion
Ā 
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
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 - RJLeonardo Balter
Ā 

What's hot (20)

Django a whirlwind tour
Django   a whirlwind tourDjango   a whirlwind tour
Django a whirlwind tour
Ā 
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 Rest Framework and React and Redux, Oh My!
Ā 
Django - ꬔ恮äø€ę­© gumiStudy#3
Django - ꬔ恮äø€ę­© gumiStudy#3Django - ꬔ恮äø€ę­© gumiStudy#3
Django - ꬔ恮äø€ę­© gumiStudy#3
Ā 
The Django Web Application Framework 2
The Django Web Application Framework 2The Django Web Application Framework 2
The Django Web Application Framework 2
Ā 
Django
DjangoDjango
Django
Ā 
Building a Dynamic Website Using Django
Building a Dynamic Website Using DjangoBuilding a Dynamic Website Using Django
Building a Dynamic Website Using Django
Ā 
Create responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJSCreate responsive websites with Django, REST and AngularJS
Create responsive websites with Django, REST and AngularJS
Ā 
The effective use of Django ORM
The effective use of Django ORMThe effective use of Django ORM
The effective use of Django ORM
Ā 
Working with the django admin
Working with the django admin Working with the django admin
Working with the django admin
Ā 
jQuery from the very beginning
jQuery from the very beginningjQuery from the very beginning
jQuery from the very beginning
Ā 
jQuery in 15 minutes
jQuery in 15 minutesjQuery in 15 minutes
jQuery in 15 minutes
Ā 
OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010OSCON Google App Engine Codelab - July 2010
OSCON Google App Engine Codelab - July 2010
Ā 
Overlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh MyOverlays, Accordions & Tabs, Oh My
Overlays, Accordions & Tabs, Oh My
Ā 
A Little Backbone For Your App
A Little Backbone For Your AppA Little Backbone For Your App
A Little Backbone For Your App
Ā 
jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009jQuery Loves Developers - Oredev 2009
jQuery Loves Developers - Oredev 2009
Ā 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
Ā 
Djangocon 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 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
Ā 
A Dexterity Intro for Recovering Archetypes Addicts
A Dexterity Intro for Recovering Archetypes AddictsA Dexterity Intro for Recovering Archetypes Addicts
A Dexterity Intro for Recovering Archetypes Addicts
Ā 
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...
And now you have two problems. Ruby regular expressions for fun and profit by...
Ā 
Realize mais com HTML 5 e CSS 3 - 16 EDTED - RJ
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
Ā 

Viewers also liked

Django in the Real World
Django in the Real WorldDjango in the Real World
Django in the Real WorldJacob Kaplan-Moss
Ā 
12 tips on Django Best Practices
12 tips on Django Best Practices12 tips on Django Best Practices
12 tips on Django Best PracticesDavid Arcos
Ā 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksShawn Rider
Ā 
Getting Started With Django
Getting Started With DjangoGetting Started With Django
Getting Started With Djangojeff_croft
Ā 
Djangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£Œ
Djangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£ŒDjangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£Œ
Djangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£ŒHan Sung Kim
Ā 
Architecture at SimpleGeo: Staying Agile at Scale
Architecture at SimpleGeo: Staying Agile at ScaleArchitecture at SimpleGeo: Staying Agile at Scale
Architecture at SimpleGeo: Staying Agile at ScaleMike Malone
Ā 
Cassandra Summit 2010 Performance Tuning
Cassandra Summit 2010 Performance TuningCassandra Summit 2010 Performance Tuning
Cassandra Summit 2010 Performance Tuningdriftx
Ā 
Advanced Django Forms Usage
Advanced Django Forms UsageAdvanced Django Forms Usage
Advanced Django Forms UsageDaniel Greenfeld
Ā 
The Web map stack on Django
The Web map stack on DjangoThe Web map stack on Django
The Web map stack on DjangoPaul Smith
Ā 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC FrameworkBala Kumar
Ā 
Etsy Activity Feeds Architecture
Etsy Activity Feeds ArchitectureEtsy Activity Feeds Architecture
Etsy Activity Feeds ArchitectureDan McKinley
Ā 
Introduction to memcached
Introduction to memcachedIntroduction to memcached
Introduction to memcachedJurriaan Persyn
Ā 
Introduction To Django
Introduction To DjangoIntroduction To Django
Introduction To DjangoJay Graves
Ā 
Web Development with Python and Django
Web Development with Python and DjangoWeb Development with Python and Django
Web Development with Python and DjangoMichael Pirnat
Ā 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to RedisDvir Volk
Ā 
Scalability, Availability & Stability Patterns
Scalability, Availability & Stability PatternsScalability, Availability & Stability Patterns
Scalability, Availability & Stability PatternsJonas BonƩr
Ā 

Viewers also liked (19)

Django in the Real World
Django in the Real WorldDjango in the Real World
Django in the Real World
Ā 
12 tips on Django Best Practices
12 tips on Django Best Practices12 tips on Django Best Practices
12 tips on Django Best Practices
Ā 
Django Best Practices
Django Best PracticesDjango Best Practices
Django Best Practices
Ā 
Django Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, TricksDjango Forms: Best Practices, Tips, Tricks
Django Forms: Best Practices, Tips, Tricks
Ā 
Getting Started With Django
Getting Started With DjangoGetting Started With Django
Getting Started With Django
Ā 
Djangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£Œ
Djangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£ŒDjangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£Œ
Djangoė”œ ė°°ģš°ėŠ” ģ‰½ź³  ė¹ ė„ø ģ›¹ź°œė°œ study ģžė£Œ
Ā 
Architecture at SimpleGeo: Staying Agile at Scale
Architecture at SimpleGeo: Staying Agile at ScaleArchitecture at SimpleGeo: Staying Agile at Scale
Architecture at SimpleGeo: Staying Agile at Scale
Ā 
Cassandra Summit 2010 Performance Tuning
Cassandra Summit 2010 Performance TuningCassandra Summit 2010 Performance Tuning
Cassandra Summit 2010 Performance Tuning
Ā 
Advanced Django Forms Usage
Advanced Django Forms UsageAdvanced Django Forms Usage
Advanced Django Forms Usage
Ā 
The Web map stack on Django
The Web map stack on DjangoThe Web map stack on Django
The Web map stack on Django
Ā 
Django - Python MVC Framework
Django - Python MVC FrameworkDjango - Python MVC Framework
Django - Python MVC Framework
Ā 
Etsy Activity Feeds Architecture
Etsy Activity Feeds ArchitectureEtsy Activity Feeds Architecture
Etsy Activity Feeds Architecture
Ā 
Python/Django Training
Python/Django TrainingPython/Django Training
Python/Django Training
Ā 
Introduction to memcached
Introduction to memcachedIntroduction to memcached
Introduction to memcached
Ā 
Introduction To Django
Introduction To DjangoIntroduction To Django
Introduction To Django
Ā 
Web Development with Python and Django
Web Development with Python and DjangoWeb Development with Python and Django
Web Development with Python and Django
Ā 
Detecting Trends
Detecting TrendsDetecting Trends
Detecting Trends
Ā 
Introduction to Redis
Introduction to RedisIntroduction to Redis
Introduction to Redis
Ā 
Scalability, Availability & Stability Patterns
Scalability, Availability & Stability PatternsScalability, Availability & Stability Patterns
Scalability, Availability & Stability Patterns
Ā 

Similar to Django Heresies

Django ļæ¼Class-based views (Slovenian)
Django ļæ¼Class-based views (Slovenian)Django ļæ¼Class-based views (Slovenian)
Django ļæ¼Class-based views (Slovenian)Luka ZakrajÅ”ek
Ā 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3giwoolee
Ā 
Django workshop : let's make a blog
Django workshop : let's make a blogDjango workshop : let's make a blog
Django workshop : let's make a blogPierre Sudron
Ā 
Š¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø Django
Š¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø DjangoŠ¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø Django
Š¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø DjangoMoscowDjango
Ā 
Django Pro ORM
Django Pro ORMDjango Pro ORM
Django Pro ORMAlex Gaynor
Ā 
Practical Celery
Practical CeleryPractical Celery
Practical CeleryCameron Maske
Ā 
What's new in Django 1.2?
What's new in Django 1.2?What's new in Django 1.2?
What's new in Django 1.2?Jacob Kaplan-Moss
Ā 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Ted Kulp
Ā 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance DjangoDjangoCon2008
Ā 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1DjangoCon2008
Ā 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneRafael Felix da Silva
Ā 
Python magicmethods
Python magicmethodsPython magicmethods
Python magicmethodsdreampuf
Ā 
Advanced Python, Part 1
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1Zaar Hai
Ā 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)tompunk
Ā 
Behind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestBehind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestDaniel Hepper
Ā 
Gae Meets Django
Gae Meets DjangoGae Meets Django
Gae Meets Djangofool2nd
Ā 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPDan Jesus
Ā 

Similar to Django Heresies (20)

Django Vs Rails
Django Vs RailsDjango Vs Rails
Django Vs Rails
Ā 
Django design-patterns
Django design-patternsDjango design-patterns
Django design-patterns
Ā 
Django ļæ¼Class-based views (Slovenian)
Django ļæ¼Class-based views (Slovenian)Django ļæ¼Class-based views (Slovenian)
Django ļæ¼Class-based views (Slovenian)
Ā 
WordPress plugin #3
WordPress plugin #3WordPress plugin #3
WordPress plugin #3
Ā 
Django workshop : let's make a blog
Django workshop : let's make a blogDjango workshop : let's make a blog
Django workshop : let's make a blog
Ā 
Š¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø Django
Š¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø DjangoŠ¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø Django
Š¢ŠµŃŃ‚ŠøрŠ¾Š²Š°Š½ŠøŠµ Šø Django
Ā 
Django Pro ORM
Django Pro ORMDjango Pro ORM
Django Pro ORM
Ā 
Practical Celery
Practical CeleryPractical Celery
Practical Celery
Ā 
What's new in Django 1.2?
What's new in Django 1.2?What's new in Django 1.2?
What's new in Django 1.2?
Ā 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101
Ā 
Django
DjangoDjango
Django
Ā 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
Ā 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1
Ā 
Aplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com BackboneAplicacoes dinamicas Rails com Backbone
Aplicacoes dinamicas Rails com Backbone
Ā 
Python magicmethods
Python magicmethodsPython magicmethods
Python magicmethods
Ā 
Advanced Python, Part 1
Advanced Python, Part 1Advanced Python, Part 1
Advanced Python, Part 1
Ā 
Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)Apostrophe (improved Paris edition)
Apostrophe (improved Paris edition)
Ā 
Behind the curtain - How Django handles a request
Behind the curtain - How Django handles a requestBehind the curtain - How Django handles a request
Behind the curtain - How Django handles a request
Ā 
Gae Meets Django
Gae Meets DjangoGae Meets Django
Gae Meets Django
Ā 
Frameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHPFrameworks da nova Era PHP FuelPHP
Frameworks da nova Era PHP FuelPHP
Ā 

More from Simon Willison

How Lanyrd does Geo
How Lanyrd does GeoHow Lanyrd does Geo
How Lanyrd does GeoSimon Willison
Ā 
Cheap tricks for startups
Cheap tricks for startupsCheap tricks for startups
Cheap tricks for startupsSimon Willison
Ā 
The Django Web Framework (EuroPython 2006)
The Django Web Framework (EuroPython 2006)The Django Web Framework (EuroPython 2006)
The Django Web Framework (EuroPython 2006)Simon Willison
Ā 
How we bootstrapped Lanyrd using Twitter's social graph
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
Ā 
Web Services for Fun and Profit
Web Services for Fun and ProfitWeb Services for Fun and Profit
Web Services for Fun and ProfitSimon Willison
Ā 
Tricks & challenges developing a large Django application
Tricks & challenges developing a large Django applicationTricks & challenges developing a large Django application
Tricks & challenges developing a large Django applicationSimon Willison
Ā 
Advanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric
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 & FabricSimon Willison
Ā 
How Lanyrd uses Twitter
How Lanyrd uses TwitterHow Lanyrd uses Twitter
How Lanyrd uses TwitterSimon Willison
Ā 
Building Things Fast - and getting approval
Building Things Fast - and getting approvalBuilding Things Fast - and getting approval
Building Things Fast - and getting approvalSimon Willison
Ā 
Rediscovering JavaScript: The Language Behind The Libraries
Rediscovering JavaScript: The Language Behind The LibrariesRediscovering JavaScript: The Language Behind The Libraries
Rediscovering JavaScript: The Language Behind The LibrariesSimon Willison
Ā 
Building crowdsourcing applications
Building crowdsourcing applicationsBuilding crowdsourcing applications
Building crowdsourcing applicationsSimon Willison
Ā 
Evented I/O based web servers, explained using bunnies
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 bunniesSimon Willison
Ā 
Cowboy development with Django
Cowboy development with DjangoCowboy development with Django
Cowboy development with DjangoSimon Willison
Ā 
Crowdsourcing with Django
Crowdsourcing with DjangoCrowdsourcing with Django
Crowdsourcing with DjangoSimon Willison
Ā 
Web App Security Horror Stories
Web App Security Horror StoriesWeb App Security Horror Stories
Web App Security Horror StoriesSimon Willison
Ā 
Web Security Horror Stories
Web Security Horror StoriesWeb Security Horror Stories
Web Security Horror StoriesSimon Willison
Ā 
When Zeppelins Ruled The Earth
When Zeppelins Ruled The EarthWhen Zeppelins Ruled The Earth
When Zeppelins Ruled The EarthSimon Willison
Ā 
When Ajax Attacks! Web application security fundamentals
When Ajax Attacks! Web application security fundamentalsWhen Ajax Attacks! Web application security fundamentals
When Ajax Attacks! Web application security fundamentalsSimon Willison
Ā 

More from Simon Willison (20)

How Lanyrd does Geo
How Lanyrd does GeoHow Lanyrd does Geo
How Lanyrd does Geo
Ā 
Cheap tricks for startups
Cheap tricks for startupsCheap tricks for startups
Cheap tricks for startups
Ā 
The Django Web Framework (EuroPython 2006)
The Django Web Framework (EuroPython 2006)The Django Web Framework (EuroPython 2006)
The Django Web Framework (EuroPython 2006)
Ā 
Building Lanyrd
Building LanyrdBuilding Lanyrd
Building Lanyrd
Ā 
How we bootstrapped Lanyrd using Twitter's social graph
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
Ā 
Web Services for Fun and Profit
Web Services for Fun and ProfitWeb Services for Fun and Profit
Web Services for Fun and Profit
Ā 
Tricks & challenges developing a large Django application
Tricks & challenges developing a large Django applicationTricks & challenges developing a large Django application
Tricks & challenges developing a large Django application
Ā 
Advanced Aspects of the Django Ecosystem: Haystack, Celery & Fabric
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
Ā 
How Lanyrd uses Twitter
How Lanyrd uses TwitterHow Lanyrd uses Twitter
How Lanyrd uses Twitter
Ā 
ScaleFail
ScaleFailScaleFail
ScaleFail
Ā 
Building Things Fast - and getting approval
Building Things Fast - and getting approvalBuilding Things Fast - and getting approval
Building Things Fast - and getting approval
Ā 
Rediscovering JavaScript: The Language Behind The Libraries
Rediscovering JavaScript: The Language Behind The LibrariesRediscovering JavaScript: The Language Behind The Libraries
Rediscovering JavaScript: The Language Behind The Libraries
Ā 
Building crowdsourcing applications
Building crowdsourcing applicationsBuilding crowdsourcing applications
Building crowdsourcing applications
Ā 
Evented I/O based web servers, explained using bunnies
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
Ā 
Cowboy development with Django
Cowboy development with DjangoCowboy development with Django
Cowboy development with Django
Ā 
Crowdsourcing with Django
Crowdsourcing with DjangoCrowdsourcing with Django
Crowdsourcing with Django
Ā 
Web App Security Horror Stories
Web App Security Horror StoriesWeb App Security Horror Stories
Web App Security Horror Stories
Ā 
Web Security Horror Stories
Web Security Horror StoriesWeb Security Horror Stories
Web Security Horror Stories
Ā 
When Zeppelins Ruled The Earth
When Zeppelins Ruled The EarthWhen Zeppelins Ruled The Earth
When Zeppelins Ruled The Earth
Ā 
When Ajax Attacks! Web application security fundamentals
When Ajax Attacks! Web application security fundamentalsWhen Ajax Attacks! Web application security fundamentals
When Ajax Attacks! Web application security fundamentals
Ā 

Recently uploaded

Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfOrbitshub
Ā 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfsudhanshuwaghmare1
Ā 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAndrey Devyatkin
Ā 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processorsdebabhi2
Ā 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWERMadyBayot
Ā 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoffsammart93
Ā 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
Ā 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Victor Rentea
Ā 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfOverkill Security
Ā 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
Ā 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FMESafe Software
Ā 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024The Digital Insurer
Ā 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Zilliz
Ā 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusZilliz
Ā 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsNanddeep Nachan
Ā 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfOverkill Security
Ā 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...apidays
Ā 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobeapidays
Ā 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc
Ā 

Recently uploaded (20)

+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
Ā 
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdfRising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Rising Above_ Dubai Floods and the Fortitude of Dubai International Airport.pdf
Ā 
Boost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdfBoost Fertility New Invention Ups Success Rates.pdf
Boost Fertility New Invention Ups Success Rates.pdf
Ā 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
Ā 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
Ā 
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWEREMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
EMPOWERMENT TECHNOLOGY GRADE 11 QUARTER 2 REVIEWER
Ā 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Ā 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
Ā 
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Finding Java's Hidden Performance Traps @ DevoxxUK 2024
Ā 
Ransomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdfRansomware_Q4_2023. The report. [EN].pdf
Ransomware_Q4_2023. The report. [EN].pdf
Ā 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Ā 
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers:  A Deep Dive into Serverless Spatial Data and FMECloud Frontiers:  A Deep Dive into Serverless Spatial Data and FME
Cloud Frontiers: A Deep Dive into Serverless Spatial Data and FME
Ā 
AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024AXA XL - Insurer Innovation Award Americas 2024
AXA XL - Insurer Innovation Award Americas 2024
Ā 
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Emergent Methods: Multi-lingual narrative tracking in the news - real-time ex...
Ā 
Exploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with MilvusExploring Multimodal Embeddings with Milvus
Exploring Multimodal Embeddings with Milvus
Ā 
MS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectorsMS Copilot expands with MS Graph connectors
MS Copilot expands with MS Graph connectors
Ā 
Cyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdfCyberprint. Dark Pink Apt Group [EN].pdf
Cyberprint. Dark Pink Apt Group [EN].pdf
Ā 
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Apidays New York 2024 - APIs in 2030: The Risk of Technological Sleepwalk by ...
Ā 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Ā 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
Ā 

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.
  • 13.
  • 14.
  • 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.ļ¬‚ickr.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 ā€¢ Conļ¬guration isnā€™t in source control!
  • 25. zoo/conļ¬gs/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.ļ¬‚ickr.com/photos/ste3ve/521083510/
  • 27.
  • 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 deļ¬ne __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 ā€œļ¬nd... | 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 ļ¬ddly ā€¢ ... 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 ļ¬le 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 ļ¬rst?
  • 63. settings.py problems ā€¢ Middleware applies globally, even to those applications that donā€™t want it ā€¢ Anything ļ¬xed 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 inļ¬nite 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