Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Django - Don't Do This!

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
Tweet

More Decks by Ash Christopher

Other Decks in Technology

Transcript

  1. [email protected]
    @ashchristopher
    DONT
    DO
    THIS!
    Friday, 20 January, 12

    View Slide

  2. Who am I?
    Friday, 20 January, 12

    View Slide

  3. Systems Analyst
    Friday, 20 January, 12

    View Slide

  4. Senior Developer
    and Team Lead
    Friday, 20 January, 12

    View Slide

  5. Senior Developer
    Friday, 20 January, 12

    View Slide

  6. What is this
    talk about?
    Friday, 20 January, 12

    View Slide

  7. Common Mistakes
    Friday, 20 January, 12

    View Slide

  8. Common mistakes as a result
    of gaining more experience
    with Django
    Friday, 20 January, 12

    View Slide

  9. Common mistakes as a result
    of gaining more experience
    with Django
    (in no particular order)
    Friday, 20 January, 12

    View Slide

  10. Friday, 20 January, 12

    View Slide

  11. Don’t be *this* guy.
    Friday, 20 January, 12

    View Slide

  12. Defining Models
    without indexes
    Friday, 20 January, 12

    View Slide

  13. DON’T forget
    your indexes
    Friday, 20 January, 12

    View Slide

  14. Models
    Friday, 20 January, 12

    View Slide

  15. Models
    They define your data.
    Friday, 20 January, 12

    View Slide

  16. Models
    They don’t define behavior.
    Friday, 20 January, 12

    View Slide

  17. Models
    They can’t read your mind.
    Friday, 20 January, 12

    View Slide

  18. Even seasoned Django
    developers forget about
    indexes
    Friday, 20 January, 12

    View Slide

  19. Remember this?
    Friday, 20 January, 12

    View Slide

  20. Remember this?
    Friday, 20 January, 12

    View Slide

  21. DO add indexes
    to your Models.
    Friday, 20 January, 12

    View Slide

  22. Over-Indexing
    Friday, 20 January, 12

    View Slide

  23. DON’T index
    everything
    Friday, 20 January, 12

    View Slide

  24. What are indexes?
    Friday, 20 January, 12

    View Slide

  25. What are indexes?
    They are pointers to your data
    Friday, 20 January, 12

    View Slide

  26. What are indexes?
    They are pointers to your data
    ... in memory
    Friday, 20 January, 12

    View Slide

  27. What are indexes?
    They are pointers to your data
    ... in memory
    ... or on disk!!!
    Friday, 20 January, 12

    View Slide

  28. They slow down inserts,
    updates and deletes.
    Friday, 20 January, 12

    View Slide

  29. As a general rule, you
    want an index on
    anything you will use
    to limit results
    Friday, 20 January, 12

    View Slide

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

    View Slide

  31. You need to assess your
    specific needs.
    Friday, 20 January, 12

    View Slide

  32. DO analyze
    your QuerySets
    to determine
    where indexes
    are needed.
    Friday, 20 January, 12

    View Slide

  33. Silly Shortcuts
    Friday, 20 January, 12

    View Slide

  34. DON’T use
    locals() to
    populate your
    context
    Friday, 20 January, 12

    View Slide

  35. I PITY THE FOOL...
    WHO HAS TO DEBUG
    YOUR TEMPLATE
    Friday, 20 January, 12

    View Slide

  36. It’s not clever.
    Friday, 20 January, 12

    View Slide

  37. It’s just lazy.
    Friday, 20 January, 12

    View Slide

  38. Every time you use
    locals() to populate your
    context, God kills a kitten.
    Friday, 20 January, 12

    View Slide

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

    View Slide

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

    View Slide

  41. context = {'context': ,
    'ipdb': __init__.pyc'>,
    'message': "Three's a crowd.",
    'num_users': 9,
    'pprint': ,
    'request': GET:,
    POST:,
    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

    View Slide

  42. '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;\\[email protected]\\h: \\w\\a\\]${debian_chroot:+($debian_chroot)}\\[email protected]\\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

    View Slide

  43. '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': ', mode 'w' at 0xb77600d0>,
    'wsgi.file_wrapper': ,
    'wsgi.input': ,
    'wsgi.multiprocess': False,
    'wsgi.multithread': True,
    'wsgi.run_once': False,
    'wsgi.url_scheme': 'http',
    'wsgi.version': (1, 0)}>,
    'users': [, , ,
    , , , ,
    , ]}
    Friday, 20 January, 12

    View Slide

  44. Weird stuff happens.
    Friday, 20 January, 12

    View Slide

  45. Did you notice?
    'context':
    Friday, 20 January, 12

    View Slide

  46. Did you notice?
    'context':
    context
    Friday, 20 January, 12

    View Slide

  47. Did you notice?
    'context':
    context [‘context’]
    Friday, 20 January, 12

    View Slide

  48. Did you notice?
    'context':
    context [‘context’] [‘context’]
    Friday, 20 January, 12

    View Slide

  49. Did you notice?
    'context':
    context [‘context’] [‘context’] [‘context’]
    Friday, 20 January, 12

    View Slide

  50. Did you notice?
    'context':
    context [‘context’] [‘context’] [‘context’] ...
    Friday, 20 January, 12

    View Slide

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

    View Slide

  52. DO define your
    context explicitly
    Friday, 20 January, 12

    View Slide

  53. Replacing the .all()
    method on QuerySets
    Friday, 20 January, 12

    View Slide

  54. DON’T replace
    get_query_set()
    with something
    unexpected.
    Friday, 20 January, 12

    View Slide

  55. The majority of
    developers and apps
    expect objects.all() to
    return ALL objects.
    Friday, 20 January, 12

    View Slide

  56. That’s why it’s called .all()
    Friday, 20 January, 12

    View Slide

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

    View Slide

  58. To get the active users:
    MyModel.objects.active()
    Friday, 20 January, 12

    View Slide

  59. What about in the
    admin?
    Friday, 20 January, 12

    View Slide

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

    View Slide

  61. DO explicitly
    define your
    QuerySets
    Friday, 20 January, 12

    View Slide

  62. Creating new ways to
    do the same things.
    Friday, 20 January, 12

    View Slide

  63. DON’T invent
    new Django
    conventions.
    Friday, 20 January, 12

    View Slide

  64. Even the best Django
    developers make this mistake
    Friday, 20 January, 12

    View Slide

  65. Even the best Django
    developers make this mistake
    Friday, 20 January, 12

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  69. oh... crap
    oh... crap
    oh... crap
    oh... crap
    Even the best Django
    developers make this mistake
    Friday, 20 January, 12

    View Slide

  70. pwned you!
    pwned you!
    pwned you!
    pwned you!
    Even the best Django
    developers make this mistake
    Friday, 20 January, 12

    View Slide

  71. ...
    ...
    ...
    ...
    Even the best Django
    developers make this mistake
    Friday, 20 January, 12

    View Slide

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

    View Slide

  73. DO follow the
    conventions
    outlined by the
    Django community
    Friday, 20 January, 12

    View Slide

  74. They have more
    experience than you
    do.
    Friday, 20 January, 12

    View Slide

  75. They have built
    more projects
    than you have.
    Friday, 20 January, 12

    View Slide

  76. They know better
    than you do.
    Friday, 20 January, 12

    View Slide

  77. Tell me I’m wrong
    Friday, 20 January, 12

    View Slide

  78. Tell me I’m wrong
    [email protected]
    @ashchristopher
    Friday, 20 January, 12

    View Slide