You are on page 1of 184

Why I Hate Django

Cal Henderson
O HAI

DjangoCon 2008 2
My happy face
DjangoCon 2008 3
DjangoCon 2008 4
2.8 billion photos

DjangoCon 2008 5
2.8 billion photos

1 per 2.3 people on earth

9.2 per US resident


DjangoCon 2008 6
35k photos/sec

>2m photos/min

DjangoCon 2008 7
Many thousand pages/sec
DjangoCon 2008 8
Scale nerd

DjangoCon 2008 9
Serious Language
DjangoCon 2008 10
Wordpress
Yahoo

Mediawiki Facebook
DjangoCon 2008 11
Wordpress
Yahoo

Delicious
Digg

Mediawiki Facebook
DjangoCon 2008 12
Flamework

Serious Toolset

DjangoCon 2008 13
Flamework Flink

Flint Flotos

Flinderbox Flictionary

Flaux Flops

Flag Fleng

DjangoCon 2008 14
Why hate Django?

DjangoCon 2008 15
What does he even know

about Django?

DjangoCon 2008 16
Pownce
DjangoCon 2008 17
A fucking blogging engine

DjangoCon 2008 18
Why all the hate?

DjangoCon 2008 19
DjangoCon 2008 20
DjangoCon 2008 21
DjangoCon 2008 22
DjangoCon 2008 23
An attack on several fronts

DjangoCon 2008 24
An attack on several fronts

The team
Python
Frameworks
DjangoCon 2008 25
Django itself

Performance

Scalability

Maintainability
DjangoCon 2008 26
The Team
DjangoCon 2008 27
Frameworks

DjangoCon 2008 28
Struts
DjangoCon 2008 29
Craig McClanahan
DjangoCon 2008 30
DjangoCon 2008 31
Exhibit A : Beard

DjangoCon 2008 32
But Struts is for suits!
DjangoCon 2008 33
The Hot Shit

DjangoCon 2008 34
DjangoCon 2008 35
Rails = Badass

DjangoCon 2008 36
Instead?

A boy band?
DjangoCon 2008 37
DjangoCore
The Album

DjangoCon 2008 38
DjangoCon 2008 39
Also, a wizard

Simon “Stinky” Willison


DjangoCon 2008 40
Python
DjangoCon 2008 41
Trendy

Google!

DjangoCon 2008 42
But not that trendy

DjangoCon 2008 43
But not that trendy

It’s no ruby

DjangoCon 2008 44
But not that trendy

It’s no ruby
Or Haskell

DjangoCon 2008 45
But not that trendy

It’s no ruby
Or Haskell
Or Erlang
DjangoCon 2008 46
But not that trendy

It’s no ruby
Or Haskell
Or Erlang
DjangoCon 2008
Or Scala 47
Significant Whitespace

DjangoCon 2008 48
DjangoCon 2008 49
Salmon

DjangoCon 2008 50
Universe of marshy force. Field sense
shallows the hatchery saying Hello,. World!.
Hydro. Power spring sometimes; snowmelt
powers snowmelt always.

DjangoCon 2008 51
DjangoCon 2008 52
No quantum
superpositions

DjangoCon 2008 53
DjangoCon 2008 54
“-”.join(array)

DjangoCon 2008 55
Restarting the server?

WTF!?
DjangoCon 2008 56
WSGIReloadMechanism
DjangoCon 2008 57
“I buy my eggs at the cheese shop”
- Aaron Straup Cope

DjangoCon 2008 58
“I buy my eggs at the cheese shop”
- Aaron Straup Cope
E ]
A G
G U
AN
L
ON
O
[M
DjangoCon 2008 59
DjangoCon 2008 60
__import__()

from future import awesome

DjangoCon 2008 61
Basically, for hippies

Scared of real

OO languages
DjangoCon 2008 62
Frameworks
DjangoCon 2008 63
Flamework is a framework

But what does that mean?

DjangoCon 2008 64
Make common tasks:

easier
faster
error-free

DjangoCon 2008 65
Show a list of photos

Write an API method

Kill all humans

DjangoCon 2008 66
Front-tier frameworks

Act as glue
DjangoCon 2008 67
Other
Services Data store

Data Model

Business
Logic

Request Interaction
Templates
Dispatcher Logic

Framework

Users

DjangoCon 2008 68
Great for getting started

Slows you down later?

What is it doing in there?


DjangoCon 2008 69
DjangoCon 2008 70
DjangoCon 2008 71
DjangoCon 2008 72
Fast
Easy

Scalable
Flexible
DjangoCon 2008 73
Large scale

is often not a good goal


DjangoCon 2008 74
Skyscrapers are special

DjangoCon 2008 75
Regular houses

Don’t need 10 story foundations

DjangoCon 2008 76
Just build!

DjangoCon 2008 77
DjangoCon 2008 78
DjangoCon 2008 79
DjangoCon 2008 80
Everything here is possible!

We care about easy


DjangoCon 2008 81
Large Scale
DjangoCon 2008 82
No multiple DB clusters

DjangoCon 2008 83
Manual partitioning
DjangoCon 2008 84
No multiple hosts per DB
DjangoCon 2008 85
Where do we read from?

DjangoCon 2008 86
How about now?

DjangoCon 2008 87
How about now ?

DjangoCon 2008 88
Read/write consistency

DjangoCon 2008 89
Read/write consistency

LAG!!1
DjangoCon 2008 90
Good for non-writing users

(logged out)
DjangoCon 2008 91
Non time-sensitive data

Feeds
Read-only APIs
DjangoCon 2008 92
DjangoCon 2008 93
Cool kids use
master/master pairs
DjangoCon 2008 94
Consistent read/write

1. Write to side A

2. Read from side B

3. Replication occurs

4. FAIL
DjangoCon 2008 95
Consistent read/write

1. Write to side A

2. Read from side A

3. ???

4. PROFIT!!
DjangoCon 2008 96
Then we can start to get fancy!
DjangoCon 2008 97
Where do we read/write?

DjangoCon 2008 98
Abstraction FTW

db_query($cluster_name, $sql)

DjangoCon 2008 99
No sharding
DjangoCon 2008 100
WTF is sharding?

All about books


DjangoCon 2008 101
Dewey Decimal
DjangoCon 2008 102
But it can’t do everything

DjangoCon 2008 103


Makes some things

‘impossible’

No shard walking
DjangoCon 2008 104
DjangoCon 2008 105
Django knows our models

It’s possible
DjangoCon 2008 106
If we accept constraints

DjangoCon 2008 107


No external sequences
DjangoCon 2008 108
Auto-incs can be bad

master/master

shards
DjangoCon 2008 109
No automatic denormalization

DjangoCon 2008 110


Counters would be easy!
DjangoCon 2008 111
And copied fields too

DjangoCon 2008 112


High
Performance
DjangoCon 2008 113
It’s slow!

DjangoCon 2008 114


DjangoCon 2008 115
DjangoCon 2008 116
There are limits

But they only apply

When being really silly


DjangoCon 2008 117
Sessions

DjangoCon 2008 118


OMG UR ON CRAK
DjangoCon 2008 119
Extra DB table

A read on every page


DjangoCon 2008 120
Lightweight = better

DjangoCon 2008 121


Signed cookies

DjangoCon 2008 122


No parallelization
DjangoCon 2008 123
Multiple cache-requests
DjangoCon 2008 124
Multiple multi-keyed reads

DjangoCon 2008 125


Slow HTTP requests while
we’re doing other stuff

DjangoCon 2008 126


Creates dumb SQL

DjangoCon 2008 127


foo.exclude(bar = true)

WHERE (NOT (bar = 1))


DjangoCon 2008 128
foo.exclude(bar = true)

WHERE bar != 1
DjangoCon 2008 129
foo.filter(bar = false)

WHERE bar = 0

Indexable!

DjangoCon 2008 130


Maintainability
DjangoCon 2008 131
Maintainability
Awesomeness
DjangoCon 2008 132
Verbose template syntax

<h1>{{ foo.bar }}</h1>


DjangoCon 2008 133
<h1>{{ foo.bar }}</h1>

<h1>{$foo.bar}</h1>

3 extra characters!
DjangoCon 2008 134
<h1>{{ foo.bar }}</h1>

<h1>{$foo.bar|e}</h1>

Well almost…
DjangoCon 2008 135
{% if edit_mode %}
woo
{% endif %}

{if $edit_mode}
woo
9 extra! {/if}
DjangoCon 2008 136
Verbose template syntax
makes people cry

DjangoCon 2008 137


No query debugger
DjangoCon 2008 138
>>> from django.db import connection
>>> connection.queries
[{'sql': 'SELECT
polls_polls.id,polls_polls.question,polls_
polls.pub_date FROM polls_polls', 'time':
'0.002'}]

DjangoCon 2008 139


>>> from django.db import connection
>>> connection.queries
[{'sql': 'SELECT
polls_polls.id,polls_polls.question,polls_
polls.pub_date FROM polls_polls', 'time':
'0.002'}]

Not good enough!


DjangoCon 2008 140
Better, but not amazing

DjangoCon 2008 141


DjangoCon 2008 142
Page summary

DjangoCon 2008 143


Make it clickable…

DjangoCon 2008 144


EXPLAIN is AWESOME
DjangoCon 2008 145
And/or show the data

DjangoCon 2008 146


MySQL Query Profiler

Enough data to

choke a whale
DjangoCon 2008 147
Not smug enough

DjangoCon 2008 148


DjangoCon 2008 149
DjangoCon 2008 150
Unreadable SQL
SELECT
`app_userprofile`.`user_id`,`app_userprofile`.`account_status`,`app_userp
rofile`.`account_status_reason`,`app_userprofile`.`account_delete_type`,`
app_userprofile`.`syndication_key`,`app_userprofile`.`blurb`,`app_userpro
file`.`location`,`app_userprofile`.`country`,`app_userprofile`.`postal_code`,`
app_userprofile`.`gender`,`app_userprofile`.`theme`,`app_userprofile`.`tiny
_photo`,`app_userprofile`.`small_photo`,`app_userprofile`.`smedium_pho
to`,`app_userprofile`.`medium_photo`,`app_userprofile`.`large_photo`,`ap
p_userprofile`.`orig_photo`,`app_userprofile`.`bday_month`,`app_userpro
file`.`bday_day`,`app_userprofile`.`bday_year`,`app_userprofile`.`is_pro`,`a
pp_userprofile`.`privacy_settings_id`,`app_userprofile`.`email_settings_id
`,`app_userprofile`.`preference_settings_id`,`app_userprofile`.`ad_counte
r`,`app_userprofile`.`num_friends`,`app_userprofile`.`num_fans`,`app_user
profile`.`num_feeds`,`app_userprofile`.`num_blocked_fans`,`app_userpro
file`.`num_friend_requests`,`app_userprofile`.`default_set_id`,`app_userpr
ofile`.`invite_id`,`app_userprofile`.`invite_round`,`app_userprofile`.`avail_in
vites`,`app_userprofile`.`original_email` FROM `app_userprofile` WHERE
(`app_userprofile`.`user_id` = 1)

DjangoCon 2008 151


Unreadable SQL
SELECT * FROM `app_userprofile` WHERE
`user_id` = 1

DjangoCon 2008 152


SELECT * is fast!

Faster over the wire


Faster to parse
Easier to debug
DjangoCon 2008 153
Unreadable SQL
SELECT
`app_note`.`id`,`app_note`.`type`,`app_note`.`body`,`app_note
`.`sender_id`,`app_note`.`date_sent`,`app_note`.`num_recipie
nts`,`app_note`.`recipient_type`,`app_note`.`set_id`,`app_not
e`.`direct_to_id`,`app_note`.`media_file_id`,`app_note`.`url`,`a
pp_note`.`url_inline`,`app_note`.`url_clicks`,`app_note`.`embe
d_id`,`app_note`.`event_id`,`app_note`.`is_direct`,`app_note`.`
is_public`,`app_note`.`is_deleted`,`app_note`.`is_ad`,`app_no
te`.`reply_to_id`,`app_note`.`forwarded_from_id`,`app_note`.`
original_note_id`,`app_note`.`stars`,`app_note`.`rsvp` FROM
`app_note` LEFT OUTER JOIN `app_userprofile_notes` AS
`m2m_app_note__recipients` ON `app_note`.`id` =
`m2m_app_note__recipients`.`note_id` WHERE ((NOT
(`app_note`.`is_deleted` = True)) AND
`m2m_app_note__recipients`.`userprofile_id` = 17573)
ORDER BY `app_note`.`date_sent` DESC LIMIT 16
DjangoCon 2008 154
Unreadable SQL
SELECT
n.*
FROM
app_note AS n
LEFT OUTER JOIN app_userprofile_notes AS l
ON
n.id=l.note_id
WHERE
n.is_deleted = False AND l.userprofile_id=17573
ORDER BY
n.date_sent DESC
LIMIT 16
DjangoCon 2008 155
Django makes me

scared of joins
DjangoCon 2008 156
Actually,

DjangoCon 2008
JOINs are evil 157
DjangoCon 2008 158
Low version number

DjangoCon 2008 159


DjangoCon 2008 160
DjangoCon 2008 161
Suspiciously small

Django: 105 klocs


Flamework: 260 klocs
DjangoCon 2008 162
Suspiciously small

Very long lines?


DjangoCon 2008 163
Can’t pluralize octopus

DjangoCon 2008 164


Commit all fields at once

DjangoCon 2008 165


Race conditions!
DjangoCon 2008 166
Dirty flags
DjangoCon 2008 167
Don’t make Malcolm cry
DjangoCon 2008 168
No simple way to inc/dec

DjangoCon 2008 169


UPDATE foo SET x=x+1

Makes consistency hard!


DjangoCon 2008 170
Character encoding
Input validation?

DjangoCon 2008 171


Character encoding
Input validation?

(Probably broken)

DjangoCon 2008 172


No mascot!?!

DjangoCon 2008 173


Echidna?

DjangoCon 2008 174


MAGICAL POWERS

DjangoCon 2008 175


No deployment system

DjangoCon 2008 176


Extending models

Tables are never


big enough
DjangoCon 2008 177
Model changes

manage.py reset appname

DjangoCon 2008 178


django-evolution

dmigrations

DjangoCon 2008 179


What’s django
done for you
lately?
DjangoCon 2008 180
thanks

(now go make it better)


Photo credits
• flickr.com/photos/wilson/18685396/ • flickr.com/photos/sharynmorrow/2571566304/
• flickr.com/photos/uhop/105063089/ • flickr.com/photos/florathexplora/286035943/
• flickr.com/photos/plasticbag/91453376/ • flickr.com/photos/webguru4god/2233500779/
• flickr.com/photos/zenoc/1408162618/ • flickr.com/photos/emdot/195189924/
• flickr.com/photos/subinev/27810058/ • flickr.com/photos/kayepants/391645870/
• flickr.com/photos/kaptainkobold/2531797176/ • flickr.com/photos/ppowers/793939285/
• flickr.com/photos/esti/243781036/ • flickr.com/photos/dinesh_valke/425540358/
• flickr.com/photos/oneras/253617128/ • flickr.com/photos/hawkexpress/306276212/
• flickr.com/photos/josefstuefer/72512671/ • flickr.com/photos/cedric1981/383614033/
• flickr.com/photos/pgoyette/168076182/ • flickr.com/photos/macspite/1118042091/
• flickr.com/photos/paulhammond/2825869449/ • flickr.com/photos/jpstanley/1440357613/
• flickr.com/photos/nez/378348754/ • flickr.com/photos/ashclements/248887492/
• flickr.com/photos/calevans/2265863104/ • flickr.com/photos/kecko/1876479840/
• flickr.com/photos/mbiddulph/416190643/ • flickr.com/photos/difusa/131100622/
• flickr.com/photos/obliterated/2249663391/ • flickr.com/photos/amagill/378984660/
• flickr.com/photos/salim/67753003/ • flickr.com/photos/bea_k63w-wa/2466009108/
• flickr.com/photos/sosalem/2816909110/ • flickr.com/photos/namullim/2096115820/
• flickr.com/photos/radiorover/324193883/ • flickr.com/photos/lotterymonkey/175248733/
• flickr.com/photos/nickwheeleroz/2773776799/ • flickr.com/photos/13519089@N03/1380483002/
• flickr.com/photos/rse/22972901/ • flickr.com/photos/gswj/10344097/
• flickr.com/photos/rougerouge/534615363/ • flickr.com/photos/deanj/67607256/
• flickr.com/photos/hawkexpress/386355092/ • flickr.com/photos/malias/2218694639/
• flickr.com/photos/escalla/438817719/ • flickr.com/photos/clintjcl/120760767/
• flickr.com/photos/mknightphoto/2295688304/ • flickr.com/photos/grandpamikey/2228239585/
• flickr.com/photos/petereed/138369750/ • flickr.com/photos/lea/2829752510/
• flickr.com/photos/superamit/196481424/

DjangoCon 2008 182


More photo credits
• flickr.com/photos/simon999/2419051858/ • flickr.com/photos/jordanroher/228435564/
• flickr.com/photos/tonyjcase/2172060723/ • flickr.com/photos/tambako/2524829095/
• flickr.com/photos/heypaul/1428681/ • flickr.com/photos/66132721@N00/2725908636/
• flickr.com/photos/swisscan/2308034084/ • flickr.com/photos/freeparking/1279927021/
• flickr.com/photos/apollonia666/310793656/ • flickr.com/photos/drurydrama/1352506223/
• flickr.com/photos/bdorfman/15846725/ • flickr.com/photos/mn_francis/397620193/
• flickr.com/photos/wishymom/566394520/ • flickr.com/photos/dramaqueennorma/273371415/
• flickr.com/photos/jgarber/121886004/ • flickr.com/photos/chasqui/2338990305/
• flickr.com/photos/eole/380316678/ • flickr.com/photos/cityhunter12/2574288725/
• flickr.com/photos/917press/1940509163/ • flickr.com/photos/akbuthod/1508537255/
• flickr.com/photos/wallyg/476718069/ • flickr.com/photos/nunoforos/2811186142/
• flickr.com/photos/biwook/390088839/ • flickr.com/photos/marcusjb/432600086/
• flickr.com/photos/bdjsb7/1674027307/ • flickr.com/photos/12495774@N02/2405297371/
• flickr.com/photos/naveenroy/314965221/ • flickr.com/photos/larimdame/572477975/
• flickr.com/photos/wyldkyss/2757474674/ • flickr.com/photos/harryharris/1525946537/
• flickr.com/photos/orinrobertjohn/409812627/ • flickr.com/photos/davemorris/91808851/
• flickr.com/photos/candiedwomanire/1651870/ • flickr.com/photos/aplumb/121285138/
• flickr.com/photos/dalvenjah/408497650/ • flickr.com/photos/peebot/825451566/
• flickr.com/photos/krikit/2657457178/ • flickr.com/photos/reillyb/2216541900/
• flickr.com/photos/w5nyv/2370344/ • flickr.com/photos/steffe/423086866/
• flickr.com/photos/jordanfischer/72510316/ • flickr.com/photos/ciordia/255983919/
• flickr.com/photos/tedsblog/91531710/ • flickr.com/photos/wwworks/2472230611/
• flickr.com/photos/celesterc/1069893367/ • flickr.com/photos/pnoid00/1909096140/
• flickr.com/photos/spacematters/766372252/ • flickr.com/photos/jurvetson/2229899/
• flickr.com/photos/esti/147733640/ • flickr.com/photos/foxypar4/766801643/
• flickr.com/photos/rbp/2833593771/ • flickr.com/photos/wizardhere/2413404079/

DjangoCon 2008 183


these slides are online:

iamcal.com/talks

DjangoCon 2008 184

You might also like