Django Don't Do This - DjangoToronto - January, 2012
-
Upload
ash-christopher -
Category
Technology
-
view
7.184 -
download
0
description
Transcript of Django Don't Do This - DjangoToronto - January, 2012
Who am I?
Friday, 20 January, 12
Systems Analyst
Friday, 20 January, 12
Senior Developer and Team Lead
Friday, 20 January, 12
Senior Developer
Friday, 20 January, 12
What is this talk about?
Friday, 20 January, 12
Common Mistakes
Friday, 20 January, 12
Common mistakes as a result of gaining more experience
with Django
Friday, 20 January, 12
Common mistakes as a result of gaining more experience
with Django
(in no particular order)
Friday, 20 January, 12
Friday, 20 January, 12
Don’t be *this* guy.
Friday, 20 January, 12
Defining Models without indexes
Friday, 20 January, 12
DON’T forget your indexes
Friday, 20 January, 12
Models
Friday, 20 January, 12
ModelsThey define your data.
Friday, 20 January, 12
ModelsThey don’t define behavior.
Friday, 20 January, 12
ModelsThey can’t read your mind.
Friday, 20 January, 12
Even seasoned Django developers forget about
indexes
Friday, 20 January, 12
Remember this?
Friday, 20 January, 12
Remember this?
Friday, 20 January, 12
DO add indexes to your Models.
Friday, 20 January, 12
Over-Indexing
Friday, 20 January, 12
DON’T index everything
Friday, 20 January, 12
What are indexes?
Friday, 20 January, 12
What are indexes?They are pointers to your data
Friday, 20 January, 12
What are indexes?They are pointers to your data
... in memory
Friday, 20 January, 12
What are indexes?They are pointers to your data
... in memory
... or on disk!!!
Friday, 20 January, 12
They slow down inserts, updates and deletes.
Friday, 20 January, 12
As a general rule, you want an index on
anything you will use to limit results
Friday, 20 January, 12
As a general rule, you want an index on
anything you will use to limit results
... but generalizations break down quickly.
Friday, 20 January, 12
You need to assess your specific needs.
Friday, 20 January, 12
DO analyze your QuerySets
to determine where indexes
are needed.Friday, 20 January, 12
Silly Shortcuts
Friday, 20 January, 12
DON’T use locals() to
populate your context
Friday, 20 January, 12
I PITY THE FOOL...WHO HAS TO DEBUG
YOUR TEMPLATE
Friday, 20 January, 12
It’s not clever.
Friday, 20 January, 12
It’s just lazy.
Friday, 20 January, 12
Every time you use locals() to populate your
context, God kills a kitten.Friday, 20 January, 12
def my_view(request):! users = User.objects.filter(active=True)! num_users = len(users)
! message = None! if num_users > 3:! ! message = "Three's a crowd." context = locals()! return render_to_response( '/path/to/template.html', context)
Friday, 20 January, 12
def my_view(request):! users = User.objects.filter(active=True)! num_users = len(users)
! message = None! if num_users > 3:! ! message = "Three's a crowd." context = locals()! return render_to_response( '/path/to/template.html', context)
Thumbs down!
Friday, 20 January, 12
context = {'context': <Recursion on dict with id=175092300>, 'ipdb': <module 'ipdb' from '/home/vagrant/.virtualenvs/wave/lib/python2.6/site-packages/ipdb/__init__.pyc'>, 'message': "Three's a crowd.", 'num_users': 9, 'pprint': <function pprint at 0x8a88f44>, 'request': <WSGIRequestGET:<QueryDict: {}>,POST:<QueryDict: {}>,COOKIES:{'__utma': '111872281.606618788.1318529036.1326747382.1326750603.150', '__utmc': '111872281', '__utmz': '111872281.1318529036.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)', 'csrftoken': '********************************', 'sessionid': '********************************'},META:{'CELERY_LOADER': 'djcelery.loaders.DjangoLoader', 'CONTENT_LENGTH': '', 'CONTENT_TYPE': 'text/plain', 'CSRF_COOKIE': '********************************', 'DJANGO_SETTINGS_MODULE': 'waveaccounting.settings', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HOME': '/home/vagrant', 'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'HTTP_ACCEPT_CHARSET': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_ACCEPT_LANGUAGE': 'en-us,en;q=0.5', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': 'csrftoken=********************************; __utma=111872281.606618788.1318529036.1326747382.1326750603.150; __utmz=111872281.1318529036.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); sessionid=********************************; __utmc=111872281', 'HTTP_HOST': 'localhost:8000', 'HTTP_USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:9.0.1) Gecko/20100101 Firefox/9.0.1', 'LANG': 'en_US.UTF-8', 'LESSCLOSE': '/usr/bin/lesspipe %s %s', 'LESSOPEN': '| /usr/bin/lesspipe %s', 'LOGNAME': 'vagrant',
Friday, 20 January, 12
'LS_COLORS': 'rs=0:di=01;34:ln=01;36:hl=44;37:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.axa=00;36:*.oga=00;36:*.spx=00;36:*.xspf=00;36:', 'MAIL': '/var/mail/vagrant', 'OLDPWD': '/home/vagrant', 'PATH': '/home/vagrant/.virtualenvs/wave/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/opt/ruby/bin/', 'PATH_INFO': u'/en/settings/business/1/', 'PIP_RESPECT_VIRTUALENV': 'true', 'PS1': '(wave)\\[\\e]0;\\u@\\h: \\w\\a\\]${debian_chroot:+($debian_chroot)}\\u@\\h:\\w\\$ ', 'PWD': '/home/vagrant/Projects/wa/waveaccounting', 'QUERY_STRING': '', 'REMOTE_ADDR': '10.0.2.2', 'REMOTE_HOST': '', 'REQUEST_METHOD': 'GET', 'RUN_MAIN': 'true', 'SCRIPT_NAME': u'', 'SERVER_NAME': 'lucid32', 'SERVER_PORT': '8000', 'SERVER_PROTOCOL': 'HTTP/1.1',
Friday, 20 January, 12
'SERVER_SOFTWARE': 'WSGIServer/0.1 Python/2.6.5', 'SHELL': '/bin/bash', 'SHLVL': '1', 'SSH_CLIENT': '10.0.2.2 50056 22', 'SSH_CONNECTION': '10.0.2.2 50056 10.0.2.15 22', 'SSH_TTY': '/dev/pts/2', 'TERM': 'xterm-256color', 'TZ': 'America/Toronto', 'USER': 'vagrant', 'VIRTUALENVWRAPPER_HOOK_DIR': '/home/vagrant/.virtualenvs', 'VIRTUALENVWRAPPER_LOG_DIR': '/home/vagrant/.virtualenvs', 'VIRTUAL_ENV': '/home/vagrant/.virtualenvs/wave', 'WORKON_HOME': '/home/vagrant/.virtualenvs', '_': '/home/vagrant/.virtualenvs/wave/bin/python', 'wsgi.errors': <open file '<stderr>', mode 'w' at 0xb77600d0>, 'wsgi.file_wrapper': <class 'django.core.servers.basehttp.FileWrapper'>, 'wsgi.input': <socket._fileobject object at 0x9c602ec>, 'wsgi.multiprocess': False, 'wsgi.multithread': True, 'wsgi.run_once': False, 'wsgi.url_scheme': 'http', 'wsgi.version': (1, 0)}>, 'users': [<User: [email protected]>, <User: [email protected]>, <User: [email protected]>, <User: [email protected]>, <User: [email protected]>, <User: [email protected]>, <User: [email protected]>, <User: >, <User: [email protected]>]}
Friday, 20 January, 12
Weird stuff happens.
Friday, 20 January, 12
Did you notice? 'context': <Recursion on dict with id=175092300>
Friday, 20 January, 12
Did you notice? 'context': <Recursion on dict with id=175092300>
context
Friday, 20 January, 12
Did you notice? 'context': <Recursion on dict with id=175092300>
context [‘context’]
Friday, 20 January, 12
Did you notice? 'context': <Recursion on dict with id=175092300>
context [‘context’] [‘context’]
Friday, 20 January, 12
Did you notice? 'context': <Recursion on dict with id=175092300>
context [‘context’] [‘context’] [‘context’]
Friday, 20 January, 12
Did you notice? 'context': <Recursion on dict with id=175092300>
context [‘context’] [‘context’] [‘context’] ...
Friday, 20 January, 12
Please... do it this way!def my_view(request):! users = User.objects.filter(active=True)! num_users = len(users)
! message = None! if num_users > 3:! ! message = "Three's a crowd."
! context = {! ! 'message' : message,! }! return render_to_response( '/path/to/template.html', context)
Friday, 20 January, 12
DO define your context explicitly
Friday, 20 January, 12
Replacing the .all() method on QuerySets
Friday, 20 January, 12
DON’T replace get_query_set()
with something unexpected.
Friday, 20 January, 12
The majority of developers and apps expect objects.all() to
return ALL objects.
Friday, 20 January, 12
That’s why it’s called .all()
Friday, 20 January, 12
EXAMPLE
class CustomQuerySet(QuerySet): def active(self): return self.filter(is_active=True)
class MyManager(models.Manager): def get_query_set(self): return CustomQuerySet(self.model)
Friday, 20 January, 12
To get the active users:
MyModel.objects.active()
Friday, 20 January, 12
What about in the admin?
Friday, 20 January, 12
What about in the admin?
class CustomModelAdmin(admin.ModelAdmin):
def queryset(self, request): “”” Only superusers can access all objects in the admin. “”” qs = super(CustomModelAdmin, self).queryset(request) if not request.user.is_superuser: qs = qs.active() return qs
Friday, 20 January, 12
DO explicitly define your QuerySets
Friday, 20 January, 12
Creating new ways to do the same things.
Friday, 20 January, 12
DON’T invent new Django
conventions.
Friday, 20 January, 12
Even the best Django developers make this mistake
Friday, 20 January, 12
Even the best Django developers make this mistake
Friday, 20 January, 12
are you sure that'sa good idea?are you sure that'sa good idea?are you sure that'sa good idea?are you sure that'sa good idea?
Even the best Django developers make this mistake
Friday, 20 January, 12
i think its a really goodusage patterni think its a really goodusage patterni think its a really goodusage patterni think its a really goodusage pattern
Even the best Django developers make this mistake
Friday, 20 January, 12
your POST data doesn'tnecessarily exist.your POST data doesn'tnecessarily exist.your POST data doesn'tnecessarily exist.your POST data doesn'tnecessarily exist.
Even the best Django developers make this mistake
Friday, 20 January, 12
oh... crapoh... crapoh... crapoh... crap
Even the best Django developers make this mistake
Friday, 20 January, 12
pwned you!pwned you!pwned you!pwned you!
Even the best Django developers make this mistake
Friday, 20 January, 12
............
Even the best Django developers make this mistake
Friday, 20 January, 12
FOLLOW THE PATTERN, BITCHES!FOLLOW THE PATTERN, BITCHES!FOLLOW THE PATTERN, BITCHES!FOLLOW THE PATTERN, BITCHES!
Even the best Django developers make this mistake
Friday, 20 January, 12
DO follow the conventions
outlined by the Django community
Friday, 20 January, 12
They have more experience than you
do.
Friday, 20 January, 12
They have built more projects than you have.
Friday, 20 January, 12
They know better than you do.
Friday, 20 January, 12
Tell me I’m wrong
Friday, 20 January, 12
Tell me I’m wrong
@ashchristopher
Friday, 20 January, 12