Slide 1

Slide 1 text

Django 101 Kenneth Love • @kennethlove

Slide 2

Slide 2 text

I teach Python, Django, and other stuff for Treehouse I’m writing a book for No Starch Press I’ve been co-organizing Django Girls Portland

Slide 3

Slide 3 text

And I’m happy to be here!

Slide 4

Slide 4 text

So, I can’t do this tutorial alone. Y’all have to ask questions every step of the way. Yes, that might mean we don’t get all the way through. That’s OK. Twitter, CodeNewbie, etc

Slide 5

Slide 5 text

This is going to be a high level overview of Django with some sudden dips and turns to keep you on your feet and feeling a bit nauseous

Slide 6

Slide 6 text

This is gonna be fairly hands-off, though, because code inflates time so much. I’ll show examples, though. A lot of the examples will be pseudocode, though. Of course, that means it’ll still look like Python!

Slide 7

Slide 7 text

Django is a framework for building web apps. It can be used for other stuff, too, but this is what it’s best at. Came from the world of newspapers/publishing and that still influences it

Slide 8

Slide 8 text

Large landmasses AKA the stuff you’ll read about the most Django has a few major pieces

Slide 9

Slide 9 text

The ORM The ORM (object relational mapper) is how Django turns Python into database records and vice versa. This includes the “model” or “M” part of MVC

Slide 10

Slide 10 text

Forms Forms are used to create HTML-based inputs for users to use. They’re also use, better IMO, to validate data

Slide 11

Slide 11 text

Templates Templates combine variables, context processors (we’ll get to them later), and text to generate a single output file. Usually this file is HTML but it doesn’t have to be. Templates are called “views” in other frameworks

Slide 12

Slide 12 text

Views Views are the transition layer between HTTP requests and HTTP responses. In most other frameworks, they’re called “controllers”.

Slide 13

Slide 13 text

Admin And, finally, the admin is a really handy tool that Django gives you for doing data entry. It’s pretty full-featured out of the box and can be heavily customized.

Slide 14

Slide 14 text

Projects & Apps Two more words to get used to

Slide 15

Slide 15 text

Project A project is your whole entire web app or site or whatever. It’s all of the Django bits and bobs together in one package.

Slide 16

Slide 16 text

dieter db.sqlite3 manage.py dieter __init__.py settings.py urls.py wsgi.py When I say “project” or “project-wide” or “project-level”, this is the file structure of what I’m talking about. An overarching directory that holds your database (assuming you’re using sqlite3 for development), the stubby fake app where your settings live, and the manage.py file for running commands.

Slide 17

Slide 17 text

App An app, though, is just one piece of the project. An app generally encompasses a single idea in your app. If you’re making a site for diets, meals, exercise, etc would be the apps.

Slide 18

Slide 18 text

meals __init__.py migrations admin.py apps.py models.py tests.py views.py templates And an app’s structure is something like this. All the pieces you need to express a software idea.

Slide 19

Slide 19 text

Why make a new app? It’s usually all about the models Apps are mostly defined by their models. Less is more, most of the time. Your app should have 1 or 2 main models and you generally name the app after the model, pluralized. If your main model is “Meal”, your app would be “meals”. When you find yourself creating a ton of models for an app, that’s a good time to re-evaluate the app and the models and decide if they should be split up. If you find yourself make a model that doesn’t really relate to the other models, you probably need a new app. A lot of this comes with experience, though, and like most things in programming, especially Python and Django, if it feels hard to do, it’s probably not the right solution.

Slide 20

Slide 20 text

Meal Recipe Ingredient Gym Exercise Let’s pretend that we have all of these models in one app. Would it make sense to break them up into two or more apps?

Slide 21

Slide 21 text

Meal Recipe Ingredient Gym Exercise Sure, probably two apps: one that’s about food and another that’s about activity

Slide 22

Slide 22 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 23

Slide 23 text

Models & the ORM So let’s talk about how we hold onto data, since that’s what most web apps are all about

Slide 24

Slide 24 text

Models Models are classes that relate, pretty closely, to database tables. They have fields that represent the columns in a table and each record is a row in the table

Slide 25

Slide 25 text

Queries Queries manipulate data. They create new records, update, or delete existing records. They also let you filter and find records.

Slide 26

Slide 26 text

Exercise.objects.create(…) Recipe.objects.filter(…) Ingredient.objects.get(…).delete() Where I have the ellipses is where you’d have your conditions or attributes. Let me show you an example of each.

Slide 27

Slide 27 text

Exercise.objects.create( name=“Light walk”, description=“A stroll around the neighborhood” duration=30, difficulty=1, intensity=1 ) Here I’m creating an Exercise. Once Django evaluates this, there’ll be a new record in the database.

Slide 28

Slide 28 text

Recipe.objects.filter( ingredients__ingredient__name__icontains=‘spinach’, cook_time__lte=60, prep_time__lte=15 ) And here I’m looking for a recipe that includes spinach, takes an hour or less to cook, and can be prepped in 15 minutes or less.

Slide 29

Slide 29 text

Did you notice the .objects? That’s a model manager and it controls what actions are available on a model. The default one has things like filter, delete, etc. You can make your own if you want to have special actions for your models Querysets?

Slide 30

Slide 30 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 31

Slide 31 text

Inheritance Sometimes your models have a lot in common. So much so, in fact, that it doesn’t make sense to repeat all of those fields. Django has two types of inheritance.

Slide 32

Slide 32 text

Multi-table Multiple table inheritance, or MTI, creates multiple tables. You might have guessed that from the name. MTI creates a table for every model and automatically creates a relationship between the child models and the parent model. Here’s an example:

Slide 33

Slide 33 text

Message: created_at created_by content Email(Message): to_address SMS(Message): to_number This would create three database tables, one for each model. But if you had an Email record selected, you could go through the “message” OneToOne field to get to the created_at, created_by, and content fields.

Slide 34

Slide 34 text

Abstract Abstract inheritance doesn’t create new database tables. Child models get all of the fields of the parent models, though. Here’s an example that might be familiar

Slide 35

Slide 35 text

Message: created_at created_by content class Meta: abstract = True Email(Message): to_address SMS(Message): to_number This will only create two tables. Both the Email and SMS tables will have their own created_at, created_by, and content columns.

Slide 36

Slide 36 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 37

Slide 37 text

Relationships Did you notice the ForeignKey fields in some of the example models? And I mentioned a “message” OneToOne” field for MTI inheritance? Django models have a few really useful ways to connect records together.

Slide 38

Slide 38 text

Foreign Key The most common is the foreign key relationship. Depending on which side of it you’re on, it can also be called a “one to many” or “many to one” relationship. If you had a Star instance, it could have many Planet instances related to it. A Planet instance, though, would only have one Star it was related to. …let’s ignore binary and trinary systems, OK?

Slide 39

Slide 39 text

One to One Remember the MTI scheme? Like I said then, these related models come with a one-to-one relationship automatically set up. One-to-one relationships are almost like having an entire other record as an attribute on your record. They’re just foreign keys under the hood but they’re unique. Each record only relates to one other record and vice versa. One of the best examples for 1-to-1 relationships is a profile model. Back before Django had custom user models, if you wanted to store some extra bit of info about a user, you had to make a new model and you’d give it a OneToOneField to the User model. When you created a new user, you’d create a new profile instance, too.

Slide 40

Slide 40 text

Many to Many The next kind of relationship is a Many to Many. M2M relationships let you have lots of related records that can also be related to lots of other records themselves. One of the most useful parts of of M2M records is the through table. Normally, Django creates a through table for you automatically that has a foreign key to each of the related tables. But you can make your own through table if you want that holds other bits of data. For example, this UserExercise table for linking users to exercises with an extra field that’ll log when each record is created. Now, normally you’d have a ManyToMany field on your model. I’m not using one here so that means I’ll have to make this record manually each time. Eh, you win some, you lose some.

Slide 41

Slide 41 text

Generic Foreign Key And, lastly, a foreign key type that you probably shouldn’t use. Generic foreign keys, or GFKs, are foreign keys that don’t know what model they point to. This requires a couple of lookups and they’re not very performant. Also, you’re usually better served building more models than you are using GFKs. Occasionally they are legitimately needed, though, usually in reusable, third-party packages

Slide 42

Slide 42 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 43

Slide 43 text

Selecting
 Related Records Every time you travel through a relationship, no matter which of the three kinds of relationship it is, you’ll have to perform another query. And that query might be a large one. There are two ways to make this a bit nicer.

Slide 44

Slide 44 text

select_related The first, and usually most useful, is select_related which does a larger query initially, using a subquery to select the related records in the same database query. Most of the time, your database will be fast enough that pulling the records there will be faster than doing an entire new query. select_related queries are done from the model that doesn’t have the foreign key on it. You add select_related onto your queries like this.

Slide 45

Slide 45 text

Recipe.objects.select_related( ‘ingredients’, ‘ingredients__ingredient’ ).filter( ingredients__ingredient__name__icontains=‘spinach’, cook_time__lte=60, prep_time__lte=15 ) You add select_related into the query and then list the fields that point to the related records. In this case, “ingredients” is the related field. Notice, too, that I went from ingredients to the ingredient that’s related through a double underscore relationship.

Slide 46

Slide 46 text

prefetch_related Since select_related is for queries to the model without the foreign key, how do you handle selecting records with the foreign key? Well, you use prefetch_related. The API is exactly the same, you list the records you want in the prefetch_related command. Instead of making a larger query, though, Django will do completely separate, extra queries and the join them together in Python.

Slide 47

Slide 47 text

RecipeIngredients.objects.prefetch_related( ‘ingredient’, ‘recipe’ ).filter( ingredient__name__icontains=‘spinach’ )

Slide 48

Slide 48 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 49

Slide 49 text

django-debug-toolbar A really handy tool for finding places where you have too many queries or queries you didn’t expect is django-debug-toolbar. [check out the 2 tag]

Slide 50

Slide 50 text

Signals One of the things you can see in django-debug-toolbar is any signals that were caused during the execution of the current view. Signals are similar to web hooks or callbacks but a bit more passive. Something happens, like a model instance is saved, and Django announces, or signals, that. Then anything that’s listening for the “model saved” signal gets evaluated. This is a great way to handle one-to-one relationships.

Slide 51

Slide 51 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 52

Slide 52 text

Forms Forms are a really handy way of getting information from users and also validating data from users or other outside sources.

Slide 53

Slide 53 text

Standard Forms You can make forms with any fields you want using the forms library. Django provides a ton of fields for all of the different types of inputs you might need to accept.

Slide 54

Slide 54 text

Model Forms Easier, though, is to use Model Forms. Model Forms turn your models into forms. This lets you automatically take model-appropriate input, pre-fill them with instance data, and save or update instances directly from a form. Models forms, though, sadly don’t call a model’s clean() method.

Slide 55

Slide 55 text

Validation So, what about validating data? Form fields automatically know how to tell if their data is the correct type. IntegerFields only take integers. URLFields have to get URLs.

Slide 56

Slide 56 text

Custom Validation Sometimes, though, you need more than the default validation.

Slide 57

Slide 57 text

Form.clean() Every form can have a method named clean(). This method is called after all of the fields have validated themselves so you can use self.cleaned_data to get all of the valid data. This is also used for cleaning multiple fields together, like making sure two password fields match

Slide 58

Slide 58 text

clean_fieldname() If you need to handle something above and beyond the default field cleaning (like making sure an integer is between 1 and 5), you can clean an individual field.

Slide 59

Slide 59 text

Validators Or you can apply a validator to a field. Django comes with a bunch of built-in validators and you can write your own, too. This is generally the best idea if you’re going to have the same kind of validation/cleaning on multiple fields in multiple forms. Your validators can be used on model fields, too, which brings me to…

Slide 60

Slide 60 text

Model clean() You can also specify how a model should clean itself. Again, once the validators on fields, and the field validation, too, have been run, whatever is in Model.clean() is run if you’re using ModelForm.clean(). Model.save() does not run Model.clean() or Model.full_clean(). Model.full_clean() checks uniqueness constraints, too.

Slide 61

Slide 61 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 62

Slide 62 text

Formsets Oh boy. Formsets let you have multiple forms all based on the same form. Maybe you have a way to add or edit multiple images attached to a blog post. Each image has an ImageField, a description, and a citation/credit field. You can use a formset to show all of the forms inside of the bigger form for editing the blog post itself. Where it gets tricky is with inline model formsets. They’re model forms, in a formset (so you have a lot of them) and they’re validated, etc, as part of the larger form. I recommend avoiding this if you can. The one place where formsets are cool is the admin. The admin takes care of pretty much all of the heavy lifting for you, so they’re not so bad.

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

OK, ready to dive down a little further? You can stop me to ask questions at any time and I’ll expect questions when you see this icon.

Slide 65

Slide 65 text

Templates Alright, let’s talk about templates. Templates are text files that Django renders into a single file. They have a bit of data that comes in that’s called “context”. They don’t have to be HTML. Django is fully capable of rendering JSON, XML, etc. Usually, though, you’re gonna want to do that stuff a more natural way.

Slide 66

Slide 66 text

{% Logic and Output }} Django templates use two types of signifiers around values and these have two different meanings. {% tags, for lack of a better work, call a bit of Python. These do things like IFs or FOR loops. Variables that are enclosed in {{ are echoed into the template. You can think of these as print() functions.

Slide 67

Slide 67 text

{{ Template|filters }} Along with the ability to print out things, Django templates can also use filters. Filters apply a bit of Python logic to a value, like capitalizing the first letter of each word or sorting a list.

Slide 68

Slide 68 text

Custom Filters Eventually, you’re gonna come up with your own transformation that you need to apply to data in your templates. You can make a custom filter! Custom filters live in your app’s templatetags directory, usually in the same module as your custom tags. Markdown thing

Slide 69

Slide 69 text

Custom Tags What was that about custom tags? Yeah, you can make your own tags, too. So if you need a templatetag that automatically renders Markdown to HTML or sends images through a bit of code that turns them into ASCII art or whatever, you can do it.

Slide 70

Slide 70 text

Simple Tags The simplest version of a custom templatetag is the simple tag. I know, surprising. Simple tags take an argument, if they need to, and then they return something that’s printed out to the template as a string.

Slide 71

Slide 71 text

Inclusion Tags One of the most common types of custom tags, though, is the inclusion tag. These tags render another template into the current template. If you’ve used PHP, this is pretty similar to using PHP’s include, require, or require_once keywords. Your inclusion tag’s template can be given a context, too, so you can send data through to it if it needs it. These are really common for things like menus.

Slide 72

Slide 72 text

Context Processor A part of Django that a lot of people don’t know about is the context processors. These are used to provide some default and extra information when you render a template. These do things like provide you with the “user” variable in your template so you can check if a user is logged in, the media and static contexts so you can refer to uploaded or static media, and the messages context so you can display flash messages to users. You can write your own context processor, too, if you find yourself needing a particular variable or value available in almost every template you render.

Slide 73

Slide 73 text

Messages Django has the ability to create temporary or flash messages for your users using something known as the messages framework. You have several types of messages: debug, info, warning, etc. These messages are stored in the session and only shown once.

Slide 74

Slide 74 text

Questions about templates or templatetags?

Slide 75

Slide 75 text

Views Alright, so this is probably our biggest subject. Let’s talk about views! Views control how Django responds to HTTP requests. They usually interact with the database, handle validating forms, rendering templates, and, eventually, returning some sort of HTTP response. That whole thing I just talked about is called the request/response cycle. Let’s take a look at it in more depth.

Slide 76

Slide 76 text

GET /recipes/5 So first the client makes a request. They say “hey, give me whatever’s at /recipes/5

Slide 77

Slide 77 text

GET /recipes/5 You’ve set up your server so that any non-static file requests (so no CSS, JavaScript, etc) get sent to a WSGI server. This is your Django’s projects wsgi.py. So now the GET request for /recipes/5 is handed to Django.

Slide 78

Slide 78 text

Middleware And now Django creates an object that represents the request and sends it through all of your middlewares. Middleware are small bits of code that can run checks against the request or manipulate it in small ways, like adding trailing slashes or making sure that all POST requests have a CSRF token. process_request, process_view

Slide 79

Slide 79 text

URLs OK, so, the request has been created and Django’s middlewares have made sure that everything is good-to-go. Now Django takes the incoming URL, minus the domain name, and starts to match it, from top to bottom in that project-wide urls.py file, to find a route that matches. If none match, Django sends out a 404 response. Assuming one matches, Django sends the request, and any variables pulled out through the route’s regex, to the view.

Slide 80

Slide 80 text

View And View & Template Middleware Now the view has the request and any variables that were in the URL. The view talks to the models, their managers, and ultimately the database. That’s all handled by the ORM, as you already know. The view pretty much always renders a template and then returns that as an HTTP response. Now Django has a response object instead of a request object.

Slide 81

Slide 81 text

Middleware And that response object goes back through the middlewares but now from bottom to top. This pass through the middleware collection handles stuff like gzipping the response. process_exception, process_template_response, process_response

Slide 82

Slide 82 text

GET /recipes/5 And then it’s back to WSGI and the server.

Slide 83

Slide 83 text

GET /recipes/5 And then the data gets back to the client. Ideally, this whole trip takes less than a second.

Slide 84

Slide 84 text

Exceptions Now, at any point in that cycle after the request gets to the view and until the response gets back to the middleware, if an exception occurs the request or response jumps over to the exception middleware. This is where you get things like the handy dandy 500 error page.

Slide 85

Slide 85 text

Questions about request/response cycle?

Slide 86

Slide 86 text

@login_required def create_recipe(request): . . . return render(request, “recipe_form.html”, {“form”: form}) As you’ve probably seen, views are often just functions. They take at least one argument, the request object, and they return something. If you’re old school, you can render a template with a Context object (big C context), and then return an HttpResponse object. Or you can just use the render() function and return that since it generates an HttpResponse object itself. Function-based views are pretty simple and very easy to get into if you’re a little comfortable with Python. If you need to protect them, Django provides some authentication decorators that you can use.

Slide 87

Slide 87 text

url(r”^recipe/create/$”, views.create_recipe) And this is how you create a URL for a function-based view. I’ll be surprised if you haven’t seen this.

Slide 88

Slide 88 text

class CreateRecipeView(views.CreateView): model = models.Recipe Alternatively, you can make views as classes. This is my preferred method but both are valid. Class-based views, or CBVs, are really handy when you have a lot of views that follow a pattern. Because of this Django provides generic views as classes that you can use.

Slide 89

Slide 89 text

url(r”^recipe/create/$”, views.CreateRecipeView.as_view() ) CBVs have a slightly different way of setting up routes for them. This is an interesting bit about views, though: they’re always, at the end of the day, a function.

Slide 90

Slide 90 text

class CreateRecipeView( mixins.LoginRequiredMixin, views.CreateView ): model = models.Recipe Unfortunately, decorating a CBV isn’t super-easy. Django provides a few mixins for adding auth requirements to your class-based views. There are mixins for requiring users to be logged in, requiring them to have a particular permission, or requiring them to pass some ad hoc test.

Slide 91

Slide 91 text

django-braces And then to pat myself on the back, if you love class-based views but want more than just authentication mixins, check out django-braces. There are mixins in there for handling prefetch_related and all sorts of other stuff.

Slide 92

Slide 92 text

Questions about function-based or class-based views or mixins?

Slide 93

Slide 93 text

Admin Alright, so, how about the admin? How many of you have used the admin? How many of you have customized the admin? First, let’s look at how to set up basic model admins.

Slide 94

Slide 94 text

fields/exclude fieldsets filter_horizontal filter_vertical inlines list_display list_display_links list_editable list_filter search_fields Let’s talk about some of the common attributes you might set on a model admin. Most of these can be controlled through methods, too, if you need to do something more custom.

Slide 95

Slide 95 text

Admin actions You’ve probably seen the default actions that are in the admin: namely you can select multiple records and then choose to delete them all. You can create custom actions, too, that act on a queryset. This is a great way to have a publish step or notify step if your app needs to control publication status or something.

Slide 96

Slide 96 text

Admin templates And, to further customize the admin, you can totally override the templates. If you have an admin/ directory in a non-project templates directory, the templates in there will be applied to the whole admin. Or you can override app-specific templates in an admin/ directory inside of the app’s templates/ directory. This is really handy if you want to, say, have a like Markdown preview or the ability to edit images inside the admin.

Slide 97

Slide 97 text

Questions about function-based or class-based views or mixins?

Slide 98

Slide 98 text

Users and security Django offers some great security and authentication bits and pieces.

Slide 99

Slide 99 text

Registration You can use Django’s built-in User class or you can write your own. Django’s registration flow is pretty customizable and packages like django-registration or django- allauth can give you a good shortcut to getting users into your site.

Slide 100

Slide 100 text

Authentication Once you have users, you’ll need to authenticate them. Django allows you to set up new authentication backends if, for example, you need to authenticate users against an LDAP or something. Authentication generally has two steps. You authenticate the user with their provided credentials, and then use the login function to actually generate their authenticated session. When they’re done, you can use the logout function to remove that authenticated session.

Slide 101

Slide 101 text

Permissions Once users are authenticated, they can be checked for permissions. Django ships with three “classes” of users. Superusers, like you make when you start your project, can do anything they want on your site. They are assumed to have all permissions. Next are authenticated users. Each of them, according to their own personal permissions and the permissions of the Group they belong to, can do particular things around your site. Maybe they can create recipes but they can’t delete them, for instance. And, lastly, Django has an anonymous user. These users are not authenticated and generally aren’t allowed to do anything. Django doesn’t come with object- or row-level permissions, so you can’t automatically say “OK, Jill, you can edit the blog posts that you wrote, but not the one’s that Omar wrote”. Packages like django-guardian make this possible and fairly easy. You can also write checks like this into your views, mixins, or model managers.

Slide 102

Slide 102 text

Passwords One of my favorite security features of Django is the password system. Django comes with a really strong password hashing algorithm already set up, PBKDF2. But, let’s fast forward 2 or 5 or 10 years to when PBKDF2 is no longer optimal, like how MD5 and SHA1 aren’t now. Django can ship a new default hasher, or you can change the hashing algo yourself, and when your user logs in for the next time, Django will update their stored hash.

Slide 103

Slide 103 text

XSS, CSRF, & Clickjacking Unrelated to users, Django offers some very handy bits of Web security out of the box. XSS, or cross-site scripting, is when someone tries to inject a bit of client-side code into your site to trick users. Maybe they run a bit of JS to capture your banking cookies. Django automatically escapes strings before displaying them, unless you turn it off (you should rarely turn it off), which stops their scriptkiddie onclick from actually being rendered as code. CSRF, cross-site request forgery, stops baddies from sending data from another site into your site, so they can’t try to get someone else’s login session for awesomesite.com by sending through a username and password from fakesite.com with a visually similar URL. CSRF generates a token that comes along with all POST requests. If Django doesn’t recognize the CSRF, or doesn’t get one, it’ll reject the request. And, lastly, clickjacking prevents your site from being displayed in a frame on someone else’s site. The baddie loads your site in a transparent iframe over a part of their site to cause you to click a button you didn’t see.

Slide 104

Slide 104 text

Questions about auth, users, security, etc

Slide 105

Slide 105 text

Gotchas, idioms, & advice This last section is a bit more freeform, just observations and knowledge I’ve picked up over the years.

Slide 106

Slide 106 text

Follow patterns If your views, forms, templates, url routes, etc are all named in the same pattern, it makes it a lot easier for new devs to come in and help and for you to predict what something will be called. Don’t name one view “create_recipe” and the next “meal_creation”.

Slide 107

Slide 107 text

Wheels exist I don’t mean Python wheels, although those are awesome, too, and you should totally use them. Django is a big community. It’s over 10 years old, too. Chances are, whatever problem you’ve run into, someone else has too. Before you start engineering some giant solution, go have a look around. This is especially true when it comes to things like async, REST apis, and caching.

Slide 108

Slide 108 text

Cache things Speaking of caching, cache things. Cache more things. Cache your queries and your compiled templates, at least, once you start getting any traffic. Django and Python are amazing but, like all dynamic languages, they’re not the fastest things around. And, while not exactly caching, make sure Python isn’t responsible for serving your static files once you’re live, too.

Slide 109

Slide 109 text

django-debug-toolbar Hey, remember this thing? Debug toolbar will get you out of a lot of problems. Use it when things get sticky.

Slide 110

Slide 110 text

DRY DRY, don’t repeat yourself. Now, this isn’t a hard-and-fast rule. It’s OK to repeat yourself sometimes. But make sure that, most of the time, when you do the same thing more than 2 or 3 times, you abstract it out into something you can reuse, whether that’s a new function, or class, or mixin, or whatever. Maybe a whole new app! This makes it easier to test, too, because now you can test a single unit once and know that it works.

Slide 111

Slide 111 text

Test Oh, and you are testing, right? Test everything you possibly can (which is a lot). Test your views, your URLs, your models, and forms if nothing else. You can save a bit of time by testing URLs and views together, sometimes even throwing in templates, but that’s not always the best idea. Still, TEST!

Slide 112

Slide 112 text

Questions?

Slide 113

Slide 113 text

Where to now? So, I’ve flooded you with all the bits and bobs of Django. Where do you go now to learn more? I have a few suggestions.

Slide 114

Slide 114 text

Online learning There are lots of great places to learn Python and Django online. Treehouse, Coursera, Codecademy, Udacity, and Udemy all have Python and Django content. Youtube has a lot, too. You can also learn through resources like Learn Python the Hard Way and the official Python and Django tutorials. Also, check out the Django Girls tutorial.

Slide 115

Slide 115 text

Books Tons of great Python and Django books out there! Hello Web App 1 and 2 Two Scoops of Django Python Crash Course Django Unleashed

Slide 116

Slide 116 text

Groups Local meetup groups, PyLadies, Django Girls, CodeNewbie. Check for bootcamps in your area, they often do open or Q&A events where you can find out more and meet other people that are interested. And, of course, all the usual social hangouts: Facebook, Twitter, and IRC.

Slide 117

Slide 117 text

Packages And other packages to check out if you just want to add more to your Django world.

Slide 118

Slide 118 text

cookiecutter-django djangorestframework django-braces django-debug-toolbar
 py.test coverage.py factory-boy

Slide 119

Slide 119 text

Questions about next steps?

Slide 120

Slide 120 text

http:/ /tiny.cc/hafpby All icons from The Noun Project Bye!