SlideShare una empresa de Scribd logo
1 de 83
Descargar para leer sin conexión
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.
{% 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/
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

Más contenido relacionado

La actualidad más candente

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
 
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
 

La actualidad más candente (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
 

Destacado

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
 

Destacado (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 a 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
 
Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Geek Moot '09 -- Smarty 101
Geek Moot '09 -- Smarty 101Ted Kulp
 
High Performance Django 1
High Performance Django 1High Performance Django 1
High Performance Django 1DjangoCon2008
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance DjangoDjangoCon2008
 
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 a 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 1
High Performance Django 1High Performance Django 1
High Performance Django 1
 
High Performance Django
High Performance DjangoHigh Performance Django
High Performance Django
 
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
 

Más de Simon 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
 

Más de 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
 

Último

Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)Gabriella Davis
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024The Digital Insurer
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking MenDelhi Call girls
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 

Último (20)

Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)A Domino Admins Adventures (Engage 2024)
A Domino Admins Adventures (Engage 2024)
 
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men08448380779 Call Girls In Civil Lines Women Seeking Men
08448380779 Call Girls In Civil Lines Women Seeking Men
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 

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.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/
  • 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 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