Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

Who am I? Friday, 20 January, 12

Slide 3

Slide 3 text

Systems Analyst Friday, 20 January, 12

Slide 4

Slide 4 text

Senior Developer and Team Lead Friday, 20 January, 12

Slide 5

Slide 5 text

Senior Developer Friday, 20 January, 12

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

Common Mistakes Friday, 20 January, 12

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

Friday, 20 January, 12

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

Defining Models without indexes Friday, 20 January, 12

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

Models Friday, 20 January, 12

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Remember this? Friday, 20 January, 12

Slide 20

Slide 20 text

Remember this? Friday, 20 January, 12

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Over-Indexing Friday, 20 January, 12

Slide 23

Slide 23 text

DON’T index everything Friday, 20 January, 12

Slide 24

Slide 24 text

What are indexes? Friday, 20 January, 12

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Silly Shortcuts Friday, 20 January, 12

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

'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

Slide 43

Slide 43 text

'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

Slide 44

Slide 44 text

Weird stuff happens. Friday, 20 January, 12

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

DO define your context explicitly Friday, 20 January, 12

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

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

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

DO explicitly define your QuerySets Friday, 20 January, 12

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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