Share
Embed
Django - Don't Do This!
Presentation created for the January 2012 Django Toronto meetup. It outlines some common mistakes that developers make as they become more familiar with the framework.
Ash Christopher
April 07, 2012
Transcript
78 slides
-
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 -
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 -
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 -
DO analyze your QuerySets to determine where indexes are needed.
Friday, 20 January, 12 -
I PITY THE FOOL... WHO HAS TO DEBUG YOUR TEMPLATE
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': <WSGIRequest GET:<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;3 1:*.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:*.rp m=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;3 5:*.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:*.mo v=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:*.vo b=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:*.fl v=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:*.a
ac=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 -
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 -
The majority of developers and apps expect objects.all() to return
ALL objects. 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 -
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 -
are you sure that's a good idea? are you sure
that's a good idea? are you sure that's a good idea? are you sure that's a good idea? Even the best Django developers make this mistake Friday, 20 January, 12 -
i think its a really good usage pattern i think
its a really good usage pattern i think its a really good usage pattern i think its a really good usage pattern Even the best Django developers make this mistake Friday, 20 January, 12 -
your POST data doesn't necessarily exist. your POST data doesn't
necessarily exist. your POST data doesn't necessarily exist. your POST data doesn't necessarily exist. Even the best Django developers make this mistake Friday, 20 January, 12 -
oh... crap oh... crap oh... crap oh... 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