SlideShare uma empresa Scribd logo
1 de 83
Baixar para ler offline
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

Mais conteúdo relacionado

Mais procurados

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
 

Mais procurados (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
 

Destaque

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
 

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

Semelhante 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
 

Semelhante 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
 

Mais 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
 

Mais 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

A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersNicole Novielli
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxLoriGlavin3
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxLoriGlavin3
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...Wes McKinney
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Nikki Chapple
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfIngrid Airi González
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPathCommunity
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfNeo4j
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesBernd Ruecker
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsNathaniel Shimoni
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality AssuranceInflectra
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesManik S Magar
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integrationmarketing932765
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024TopCSSGallery
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxLoriGlavin3
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxLoriGlavin3
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024BookNet Canada
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationKnoldus Inc.
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxLoriGlavin3
 

Último (20)

A Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software DevelopersA Journey Into the Emotions of Software Developers
A Journey Into the Emotions of Software Developers
 
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptxA Deep Dive on Passkeys: FIDO Paris Seminar.pptx
A Deep Dive on Passkeys: FIDO Paris Seminar.pptx
 
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptxPasskey Providers and Enabling Portability: FIDO Paris Seminar.pptx
Passkey Providers and Enabling Portability: FIDO Paris Seminar.pptx
 
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data PrivacyTrustArc Webinar - How to Build Consumer Trust Through Data Privacy
TrustArc Webinar - How to Build Consumer Trust Through Data Privacy
 
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
The Future Roadmap for the Composable Data Stack - Wes McKinney - Data Counci...
 
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
Microsoft 365 Copilot: How to boost your productivity with AI – Part one: Ado...
 
Generative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdfGenerative Artificial Intelligence: How generative AI works.pdf
Generative Artificial Intelligence: How generative AI works.pdf
 
UiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to HeroUiPath Community: Communication Mining from Zero to Hero
UiPath Community: Communication Mining from Zero to Hero
 
Connecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdfConnecting the Dots for Information Discovery.pdf
Connecting the Dots for Information Discovery.pdf
 
QCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architecturesQCon London: Mastering long-running processes in modern architectures
QCon London: Mastering long-running processes in modern architectures
 
Time Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directionsTime Series Foundation Models - current state and future directions
Time Series Foundation Models - current state and future directions
 
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance[Webinar] SpiraTest - Setting New Standards in Quality Assurance
[Webinar] SpiraTest - Setting New Standards in Quality Assurance
 
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotesMuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
MuleSoft Online Meetup Group - B2B Crash Course: Release SparkNotes
 
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS:  6 Ways to Automate Your Data IntegrationBridging Between CAD & GIS:  6 Ways to Automate Your Data Integration
Bridging Between CAD & GIS: 6 Ways to Automate Your Data Integration
 
Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024Top 10 Hubspot Development Companies in 2024
Top 10 Hubspot Development Companies in 2024
 
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptxThe Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
The Fit for Passkeys for Employee and Consumer Sign-ins: FIDO Paris Seminar.pptx
 
The State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptxThe State of Passkeys with FIDO Alliance.pptx
The State of Passkeys with FIDO Alliance.pptx
 
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
New from BookNet Canada for 2024: Loan Stars - Tech Forum 2024
 
Data governance with Unity Catalog Presentation
Data governance with Unity Catalog PresentationData governance with Unity Catalog Presentation
Data governance with Unity Catalog Presentation
 
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptxMerck Moving Beyond Passwords: FIDO Paris Seminar.pptx
Merck Moving Beyond Passwords: FIDO Paris Seminar.pptx
 

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