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.
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.
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?
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:
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.
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.
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.
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?
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.
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.
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
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.
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.
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.
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.
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.
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.
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
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…
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.
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.
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.
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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
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.
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.
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
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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”.
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.
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.
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.
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!
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.
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.