Closing session
Published June 13, 2025
This video features Johannes Spielmann at DjangoCon Europe 2021 in Online.
In this workshop, we are going to look at four challenges that appear in every Django project at some point. We are going to analyze what's happening, what you can do to get un-stuck, and see what other people do.
This workshop is for beginners and advanced Django users. The issues we discuss appear in many Django projects, so there is something here for every level of Django knowledge.
These are the four challenges we are going to look at:
For each of these, we will try out what I do when they happen, and we'll discuss other strategies.
We will not do a lot of coding in this workshop, but if you want to follow along, make sure you have Django installed and can execute "django-admin.py". There is also a set of base templates I am going to use for illustration, which is linked in the files below.
Of course, there are many more problems like these, which is why I made a list of "suggestions" or "best practices" for these and others.
Here's what we're working on so far:
You can find that list on Github at: https://github.com/shezi/django-unstuck (it's a work-in-progress).
There is also a Discord community and Telegram chat group surrounding that list, so if you have any kind of problem with a Django project, come join us and we'll find a way to get you unstuck.
We're building a community around Django best practices and on getting you Unstuck in challenging situations. Join us on Discord at https://discord.gg/bUsu9B6Ek6 or on Telegram at https://t.me/djangoRhein
About me: I'm Johannes Spielmann, software developer-for-hire from Germany, and I've been doing Django projects for almost 15 years, ever since I saw Adrian Holovaty's presentation at "Snakes and Rubies". I've done projects both small and large, both in commercial and non-commercial settings, and I've seen all of the above things many times.
Johannes Spielmann presents conventions he has found useful for keeping Django projects navigable as they grow. He recommends separating project configuration into a clearly named `config` package with base, development, test, and production settings; placing applications under an `apps` directory; giving every app its own URL configuration; and using consistent names across URLs, views, and templates. For templates and static files, he advocates clear project-level and app-level namespaces, shared base templates and snippets, and explicit overrides. He also explains that context processors add reusable data to every template, while middleware wraps the whole request-response cycle and is appropriate for concerns such as security headers, query monitoring, and login tracking; the recording cuts off while he is comparing further examples.
Summarised automatically from the transcript.
Automatically transcribed, so expect mistakes in names and technical terms.
Speaker 1: Welcome to my workshop Django Unstuck where I have some suggestions for common challenges in your projects. Who am I? I am Johannes Spielmann. I'm a software developer from Germany. I've been doing Django projects for 15 years now. The first version of Django that I've uh that I remember is 0. 96 And that's things changed very quickly back then. So I've done a lot of projects with Django. I have done small projects and large projects. I've done commercial projects and non-commercial projects and hobby projects. I've seen a lot of things and um I've seen all what we will talk about today many times. So um There is a lot of uh
Speaker 1: I have a lot of confidence that I can talk about the things that I'm talking about. I'm also for hire and you should definitely hire me. All right, um I'm going to try to be interactive. So if you have any questions or anything that uh is interesting or not interesting. right into the Slack channel. I'll keep my eye on the Slack channel and I'll try to answer questions as they come up. This is a workshop after all. I will also be available on the Jitsi afterwards. So if you want to talk with me. After we did all this, let me know. All right. There are challenges that come up in every Django project. And this is just true, right? There are things that happen in every Django project, and
Speaker 1: some of these start right at the beginning. How do you organize your code? How do you Do internationalization, how do you do stuff? Some appear only later once you have worked a bit with your project. Now the question is how do we get past these challenges? And I'm going to show you some of the things that I found that they work for me. Now some people might call these things best practices or patterns or recipes or ideas or opinions or any other word, but these are things that I found that work for me. They might not work for you, they might not work in every situation, but there are some ideas on how you can proceed with your challenges Now, some of the things that we're going to talk about are more code related.
Speaker 1: We are going to program a little bit, just a tiny bit. Others are more guidelines, are more suggestions on how to proceed. And today we're going to talk about four areas. We're going to talk about app management. And where do you put your apps? What do you put into your apps? How do you make sure you find them again? We're going to talk about the templates. Where do you put your templates? What do you call your templates? What do you put into your templates? um to make sure that you have an overview. And these are the two code sections. We're going to code a little bit, we're going to look a little bit at code. for apps and templates. And then we're going to go to the software topics. We're going to talk about middlewares and context processes.
Speaker 1: And there are some questions on when you should use which one and what are they in any case. And finally, we're going to talk about code structure. Where could you put your code? Where could you put your logic? Should it be in models, in views, in managers, or maybe someplace entirely different? All right. So of course there are more such things. There are more challenges and more questions that come up in every Django project. And I've collected a list of them. And I'm trying to get on top of each of them. And I do that by trying to build a community around these things. There's a GitHub link where you can see all of these things that I've collected. The list is up there. It's a work in progress. I don't have solutions for all of these yet, but with your help and with time, we'll find solutions for each of these things.
Speaker 1: There's also a Discord community if you have any problems, if you have any recurring problems, or if you have any ideas regarding recurring problems, please join us on Discord. And finally, there's a telegram group. This is the Django Rheinland User Group, which is where I'm from in the west of Germany. Please join us there as well if you want. And let's talk about your challenges and our challenges. Alright, let's start with part one. We're going to talk about app management and URL patterns and settings and how we structure our project. And for that, I'm going to start a new Django project. And um we do that with a regular Django admin. We do a start project, and we're going to call it
Speaker 1: uh some name. I had just pulled a name out of a name generator. It spit out the word toque. I hooked it up. It's it's a bubble hat. It's a woolen hat with the bubble on top. So I like the word and I kept it. And I'm going to go into my project. And uh what I usually want to do is I want to start an app right away and In these early phases of a project, I don't have many ideas on names yet. So I'm I I really want to put my code um I really want to put my code in the same name as before. Okay, there was a question about the about these links. You can look up the links in the talk description, which I have linked in the Slack a little bit higher up, about an hour ago.
Speaker 1: So you can look up these links in my talks description. All right. I want to start an app called Tuke because it's kind of the obvious name, right? And right away I do get problems because that name is already taken. We're gonna see in a second why that name is taken and how we're gonna deal with it. But I need to find a new name and I'm very creative, so I'm going to call it myTuke. Thanks for that suggestion in Slack, by the way. It's nice to know that someone's listening. All right. We've started a new Django project. Let's look at what we've got. I happen to have an IDE here. Oh, there's lots of stuff in here already. Let me get rid of that.
Speaker 1: And it should reload at some point. Okay. I forgot to clean that up before. Sorry about that. Alright, this is the project that we have Maybe if I can find all right, here's the project directory. And um I really don't like that structure. There are already lots of names that are identical. There are directories in my project where it's unclear what they do exactly. I mean of course we are all familiar with Django and we all know what these pro what these directories do. But um when our projects grow, these will be more and more unfindable. They will be more and more um problematic um to navigate them and to find everything. And especially when you s
Speaker 1: when you come into a project that's been grown growing for a little while, you'll have problems finding your way around. So the challenge for this part is we want to organize our project. And we want to organize our project in such a way that everything has its place. We want to have a place for everything and we want to be able to say this is the place for that. At the same time, we want to organize the places so that what belongs together stays together. We don't want to fish around for things that are in different places. We want to have specific places that keep things together Or specific structures. We want to make sure that our code and our URLs are easily found. We want to make sure that we can navigate our project confidently.
Speaker 1: And finally, we want to have flexibility. So this is kind of countering the other points, we want to be flexible enough that we can work with all of our stuff. Alright, let's start with step one with configuration. We're going to clean up our project structure a little bit and extract the configuration. Right now, all of the configuration for my project is in the folder called tuk, which is the same as the project name, which is the same as the project directory which I've had before. for and this is really not nice because it it's it's duplicated and I don't see what it is. So I'm going to rename that directory and I'm going to call it config. In every Django project I start, this is usually one of the first things I do. So
Speaker 1: this makes it much clearer what is in this directory, right? It's the configuration for this project. And we're going to have a lot of directories in this project directory at some point. So we want to make sure that all the top-level directories say what they are. We want to make sure that they are easily readable. Now to make our settings a bit more flexible, I want to extract them into a module and want to have different settings for different uh environments because I have at least three environments in each of my in each of my projects. I have the development environment, I have a test environment where I run my tests, and I have a production environment, which is the one that I deploy. two places and they are usually similarly configured but not exactly the same so I am going to create a new directory here
Speaker 1: and I'm going to call it settings And actually that was wrong. Let me go back. Ah, the joys of live coding. Let me create a new directory and call settings. And I'm going to move my settings in there And I'm going to change the name from settings to base. Because these are the settings that Django generated for us. And we're going to use that as the basis for all of our other settings. Now I've changed the path of this file now, so I have to change the path of the baster. Uh I have to add one more parent because we've put it one directory in and um That means we when we refer to the base
Speaker 1: there, we must refer to one directory higher up. All right. Okay, so these settings are the basis for um All of the other settings that we do. And now we can create our three different environments. The first one is going to be development. py. And I'm simply going to import all of the base settings by doing from base import everything. This means that I don't have to start doing the settings again, but instead I can change the settings. For example, one of the things that I do in here is I'll have the password validators set to an empty set. Because in development it doesn't really matter what my passwords are, right? There are other things you could do.
Speaker 1: For example, you could do installed apps and add, for example, Django extensions here. Right. I don't want the extensions to be there in the production environment, but I really want them in my development environment or the debug toolbar. Right. Everyone's using the extensions and the debug toolbar, but not in production, only in only in development. Thanks for the compliment. Alright, so these are my development settings and I can play around with them. I can I can do things here and I can be sure that they don't impact the other environments. What are the other environments? I need a test setting And I'm going to call
Speaker 1: test. py from base import everything. And now I can do test settings here. I might change the database setting. I'm not going to do that right now, but I could switch databases, I could do stuff here. That's only applicable to tests. And finally, the production settings And again, we'll import everything from base. And in here, I will usually do debug equals false. I will usually do the allowed host settings. And they will be whatever it is that my project ends up on. Putting these into the production settings
Speaker 1: mean they don't interfere with my development. Because in development I really don't want a loud host. I want to be able to call it from everywhere. But in production I really want to make sure that this is set correctly. All right. So we have to do one more step to be able to use these settings because when Django uh created the project for us. It put the settings name in here. So we have to refer to the settings that we use in the different places. And in here I am going to refer to config. settings development because usually when I use the manage. py, I will refer to development settings There are two more places that we have to edit. And this is the wsgi.
Speaker 1: py where I will refer to config settings. production. And also the ASG IDEL pile. I can still override this, right? I can still go back and say I want to set the Django settings module. and um get a different kind of settings but um we uh we usually refer to the production settings Yeah, it's it's actually quite hard to look at Slack while I'm doing this. So thanks. Thanks for noticing. All right. In these places, I will usually refer to the production settings. I can still override this by the environment variable, but this is the default setting. So now we're set. I can use my different settings here, and I have a much nicer structure in here.
Speaker 1: But we're not done with restructuring our project because now I have a set a directory called config and a directory called mytuk. And uh that's not good enough. We're going to do an apps directory. We're going to take the apps and put them into their own directory Now in a new project, this is not very impressive because it only has two directories here. But when your projects grow and we'll grow them a little bit in a minute, Uh you'll have more directories here and it'll be very good to have clear structure in here. And um to be able to um see exactly what's in your project. That's Super good. So I'm going to create a directory called apps in here. And I'm going to move my app into this directory. Now one of the good things about the name apps is that it starts with A, so this is usually at the top of the list.
Speaker 1: So another benefit. In this directory, I will put all my apps and only my apps. Now what this means is that I am free to choose any name I want in here. So I can actually rename my app into toque. It's not I'm conflicted on this name and you know that finding names for things is a hard thing. But um I sometimes call the the main app like the project, I sometimes call it core. There's really no good way to do this here. But the thing is I'm free to do that, right? I'm free to call my app whatever I want to. Now the problem is that seen from our project root, this app is not called toque anymore. It's now called Apps Took.
Speaker 1: And I don't want that. I want my apps to be able to work without modification. So what we're going to do is we're going to add this directory to our Python path. And there are a handful of places where you could do this, but a great place is to do this in the base settings, right at the top of the base settings. Because whenever Django starts executing, it will always read the settings. And the settings will always be executed before anything else. So it's a safe place to put this here. So I'm going to import sys and I'm going to do sys. path. append. And I want to refer to the base directory, which is nice because we already have the base directory. And I'm going to refer to this one.
Speaker 1: Now it works like this. This is a path and this is another path, but to make our IDE happy, I'm going to stringify that. Right? Adding this means that these this directory is now a source root directory, and I can refer to these apps by name. So whenever I add them to my installed apps, I can refer to them by their regular name, just as I would before. They are now only collected in here and this makes the structure much nicer in my opinion. Right. We're going to have um a lot of directories in the project. There will be a docs directory in here There will be a tools directory in here or a utilities or a scripts directory.
Speaker 1: We'll create a handful of directories in a minute. So having these apps separated and having the top level elements of your project Name what they are makes it much easier to find your way around these. Alright. So the last step I want to do in app management and settings is URL patterns. And uh the way URL patterns are handled in Django projects is um that you have one URLs. py Which, by the way, we have to wire up in the settings. In the settings, they were called where are they? If I can find them, I'll show it to you. Here they are. They're called uh two URLs. That's not the case anymore.
Speaker 1: They're called config. urels. All right, fixed that. And um yeah, this would be the same. We would have to refer to configure. Um you'll find these things uh when you start your project, uh Django with Hub. All right, in the URLs. I know that all my apps will have URLs. Right? So whenever I start a new app, I immediately put it in here and I immediately include um Tuke dot URLs in here. That one we need. All right. And we need to create this file. And this is always
Speaker 1: when I start an app, it always gets a URL set by actual URLs. Let's go on URLs. All right, let's create the file. py. And uh we put two things in here, an app name. And that's going to be called toque. This is important for namespacing, so you can refer to your URLs by name. And we need to create URL patterns here. Django will not allow an empty file to be a URLs file. You have to have a variable called URL patterns in here. Now I add this file to all of my apps and I immediately add all of my apps in here. This means that
Speaker 1: I can easily add new URLs, new views to my apps, and I don't have to worry about integrating them into the main project because they're already integrated. So each of my apps will have a URLs. py, even if I can't immediately see which kind of views it might have, it might have them at some point. All right. So this is something that I do for each of my apps. And each of my apps immediately goes in here, which means that I can be sure that they are included. I don't have to worry about forgetting them. Alright. So our app is almost ready, I would say. Now we can start with the templates. Now we can start thinking about where we put the templates in our app. But actually
Speaker 1: That's part two. Let's talk about templates. Where do we put our templates? Where which folders are good? Which blocks are good in templates? How do you inherit from templates and how do you make sure that they work? So the main questions we have in this section are where are your templates and what are they called? And the challenge here is that all your templates live in one big namespace. Whenever you refer to a template by name, Django will go through the list of all the template directories it has, and the first one that matches will be the one that you get. So all templates are just in a long list of all the template files that you have. But at the same time There are many places in the file system where they can go.
Speaker 1: And we will be able, we will see a handful of these places and we will decide on what to do with them. So the challenge here is we need to decide where a template file goes. For each template file, we must decide where we want to place it. We want to place them such that we can identify what a template belongs to So when I see a template file in my uh in my directories, I want to know what it does. I want to know what it what what it what it belongs to, where it where it comes from. And just given a name or a place in the file system, it's sometimes very hard to do. So we need to we need to think of a convention to that. And finally, I want to place them so that namespace clashes are minimal. I want to make sure that when I refer to a template by name, I get that template and not something else that happens to be in the same place
Speaker 1: or that happens to have the same name. Right. All right. The first step we do here is the main template directory. And this is the first directory that we're going to add to our um To our project, and we're going to call it templates. Now, to make this work, we have to add it to the settings and we're going to add it to the base settings. And conveniently, I'm already in the right place. So The the DIRs option in the template setting refers to template directories that you have. And we're simply going to add basedir slash templates here. This is going to be the only directory that we will have in here for a long time, usually.
Speaker 1: And this directory is above all the others. So anything that we place in here will be found first So anything that we place in here takes precedence over all the other things that we will do in a minute. So in this directory, we're going to put all the things that are specific to our project. Because it's a project directory, right? It's in our project. It's the templates directory. These are all the templates that belong into our project. I happen to have a handful of templates prepared and you can download them from the talk description site as well. It's not important what they are, but you might want to have them at some point. All right, what are the templates that are specific to our project? The first thing that every project has is a base
Speaker 1: template. And uh want to add that here and it's going to be base and it's going to contain the basic structure of Our page, right? It's going to contain the HTML header, it's going to contain the head and the body and the title and so on. And I use foundation So this is a base template for foundation. It's it's a regular base template. I I copied this from somewhere. It's nothing it's nothing special. But it has All the stuff needed to render a nicely laid up page. And there are a handful of tags in here. There's the title tag And what I do, now there are two things you could do with the title tag. You could add the page title after the title tag, or you could put it into the title tag.
Speaker 1: And Let's discuss this in the GT afterwards. I assume some of you will have opinions on this. Let's talk about this later. But the thing is, this one is called tidy. And it's always going to be call title because I always call my blocks like this. So this is my convention. This is the title block. Then I have some messages and I have a content block. And these two are present in all of my base templates. I'll have a page title and I have some content. And that is what makes this a base template. Now I have other base templates as well, and you will have other base templates as well. For example, here's one that's wider. It doesn't have a menu at the side. It has a menu, but it's hidden.
Speaker 1: You might have a handful of these base templates and they all go in here and you can refer to them simply by their name. So this in our project is called base. html. And this is kind of a convention to call this base. html. It's it's yeah, it's kind of a convention. Alright, these two are the most important things that go here, basis and sub-basis. But there's more. There are a handful of snippets that most projects will have, and one of them you can see in here, which is the menu structure. And I'm referring to that menu structure in a handful of places, so I've extracted it as a snippet. You can see that this is not a Super complicated menu structure, but it's giving me the base entries for my main
Speaker 1: menu on this page. And This is one of the snippets that I have. Another snippet that every project has is pagination. This is something I have to do every time. Every project needs a pagination snippet. And I I happen to have one that I use across projects, and this is the one that works for me. Really depends on the CSS and on the on the structure that you have, but this is the one that works for me. Right. So these are snippets that belong to the entire project. They're not specific to any part of our project. They're not specific to any app. They are specific to the entire project. And finally, what we put in the base template directory, in the main template directory, are overrides. Since the main template directory will be loaded before all the other template directories,
Speaker 1: we can put in here that overrides stuff from other apps. For example, the registration app. Now these are two templates that um uh applied to the Django out login views, to the built-in Django login views. So if you have the same base template as I have Or if you have the same foundation CSS loaded, this will give you a nice login page. And we I don't have to do anything else, I just have to wire up that view. Since the view um loads this template called registration login. html and this since this is in the main template directory this will be loaded automatically. Right, same goes for the logged out page. If you don't have a template for the logged out page, you'll get the admin logout page, which is sometimes confusing to the users.
Speaker 1: So these are a handful of the base templates that I usually have in my project. And they go into the main template directory because they apply to the project. All right. This was the main template directory. Next step are the in-app template directories. And it's similar to the URLs, where even if I'm not sure, or even if I think An app might not have any templates, I immediately create a directory called templates in there. And inside of that template factory, I immediately create a directory called toque Which is the same as the as the app name. Now this part is a line a little bit unfortunate.
Speaker 1: The name is duplicated and we have to do it this way. Why would we do that? To avoid namespace clashes Whenever I refer to a template inside of this directory, I can be very certain that no other template will be named like this. I can be sure that any templates I put in here will be correctly named. They will be correctly found. So I can refer to this namespace as to. Now let's create a simple template And I'm going to call it main. html. All of my templates extend based. Oops. Extends based at HTML, which means I have two blocks.
Speaker 1: I have a block called title And I have a block called content. And since I keep these names the same, I can I know that I can refer to them. I know I'm sh I'm safe in referring to these names. Call this main page and I'm just gonna put some main page in there, right? This it doesn't matter what is on here, this is just for the structure Alright, to make sure that I know what this template is for, I'm going to create a few a view function. And I'm going to create a view function that isn't called the same as this template. All right. Did does it not work anymore? I'm still I'm still doing.
Speaker 1: Um I'll I'll let's ask Miguel All right. Um I might wait a second until okay. Does yes mean that it stopped or yes that it works? All right, everything seems to be working. I can continue. Alright, in this view called main, I'm going to refer to the template called main. Um request and I'm going to refer to
Speaker 1: took main dot html. All right The wrong screen is being shared. Wow, this is weird. You should be able to see my um Yeah, it says that it shares the the IDE. It looks looks right for me. I don't know what's happening. Have we reached the zoom limit on how long we can look at each other? Yeah, that's that's not what's coming. That's not what I'm doing. Um I'm a bit further along
Speaker 1: Technical problems. The joy of doing live talks. No worries. We'll be able to get back on track. All right. There seem to be technical problems for some people. I'll continue along and if these persists, we'll we'll go back and refer them, refine them. Alright. So the the main point is here that I've created a view function called main. And this is the same name as the template's name. Which means I can now be sure that I can find this again. So if I look at the template called main, I can go into views
Speaker 1: and I can be sure that this is the main uh that the same name appears here and this is the way I tie these things together. I make sure that the template name is always called the same as the views name. And I would like to go one step further. I'd like to go here and add a path here. And um I'm going to refer to views. main here and I'm going to call this URL main. I have to import lots of stuff. I'm going to import this, I'm going to import this. Alright, let's actually import locally. It's nicer.
Speaker 1: Alright, so the name here will be the same as the name of the view function, and that will be the same as the name of the template. And this ties these three things together. This means I don't have to worry about losing my way. I don't have to worry about not finding these templates anymore. And um I can be sure that Um I can find these things again. I can be sure that these things are tied together. So this overcomes one of my challenges that I have. I want to make sure that These namespace clashes are minimized. I do that by prefixing the templates with their app name. I call them the same as their view function, and I call the URL the same. So I can refer to
Speaker 1: The um I can refer to the template by its name. Right. It seems my screen share is stuck. Um I have no idea what's happening, so someone at Loud swarm, could please look at this. I can keep talking, but you really should be able to see the things that I show you. Everyone everyone saying that my face is going, but the screen share is is stuck.
Speaker 1: Um I don't know, what should we do? Should we continue on or should we wait a few minutes? Uh
Speaker 2: sorry, John. Um did you try to
Speaker 1: jump in here just a second. I I've uh turned off everything here, so
Speaker 2: could you try to to stop and and start the share again? So
Speaker 1: yeah, sure. I've started the share. It should be a green screen saying in app template directories.
Speaker 2: Yes, okay.
Speaker 1: All right. We'll go to the next step. There should be
Speaker 2: I think that's that's okay. Again. Yeah, you can keep going.
Speaker 1: All right, many thanks to the to the team for taking care of this so quickly. And uh we'll continue on. All right, we've we've done a lot of work on the templates, and I'm going to show you the the resulting structure that we've made here again so you can see this. We have created a template called main. html. We've created a view called main and we Have wired up the URL to be the same name. And I try to do this whenever I can. It will not work all the time, but I try to do this whenever I can to have the names the same. And these names will now tie together these three places. They will tie together the URL, they will try together the template file, and they will tie together the view function.
Speaker 1: It's working now. Excellent. Thanks everyone for pointing this out and thanks for the team for jumping in so quickly. All right. So Our structure is now quite clean again, right? We have avoided namespace clashes by choosing correct namespaces, and we've made these things navigable. We've made it sure we've made sure that we can go back from the template to the view function and to the URL. So whenever I need to refer to any of these things, I have the same name. And that makes it much easier to navigate between them As I said, this is not always possible, but try to do that. It'll make your life a lot easier. Now the last step is to do the same thing. Oops, here we are. To do the same thing for static files.
Speaker 1: Static files are essentially the same. They work essentially the same as template. There's a main static files directory. There are static files in each app. You must make sure that they are namespaced correctly and that you can find them again. They work the same. Do the same thing for static files. All right So this is all that I want to talk about regarding project structure today. We've done the settings. We've Created a project structure that separates the apps. We've talked about template placement and we can now be sure that we have a nicely structured project where we can find our files again. Let's go to one of the more uh softer topics. Let's talk about middlewares and context processes.
Speaker 1: And and also we should talk about custom template tags because they kind of do things that are similar. But I don't want to talk about them right now. This is a topic that that could be its own talk. Right. What are middlewares and contacts process? And to understand what they are, we need to talk about the request and response cycle. Now, this is a drawing I did during Sarah Peter's workshop yesterday. She inspired us to do uh to draw technical concepts of Django, and I'm very happy. Actually did that. So um this is the drawing I did yesterday. And this is the Django request response cycle that we're all very familiar with. And what happens in the request response cycle? The first thing that happens is that when a request comes in, we go to the URL dispatch and the URL dispatch will select which view function will be executed.
Speaker 1: That view function will create a context, and that context will be handed to the template, and that template uh creates the response that is now sent back. to um the user. And this is this is the usual cycle, right? This is there is this is what we use every day. This is what makes Django work. And one of the things that we can add are context processors. Now sometimes you want to do things that show up in each rendered template. And this is something that context processors can do In this situation, if you are in the base in the base cycle, all you can do is you can add some context, and the context will be rendered by the template Now, if you have something that appears on every page, like a menu structure, or like the name of the logged in
Speaker 1: user, or like the current time of day or whatever you want to put in there, you have to put it into the context. And in this view, if you look at this diagram, that means your view function must put this into the context. Now this is annoying and you might forget this and and this might not work very well. So this is where context processes come in because A context processor adds to the context that is put into the template without you doing anything. The context processes are set up in your project settings. And they are executed every time a template is rendered. And they add to this context. So these are very simple things, these are very simple functions. Here's an example. You might have a shop page
Speaker 1: and you want to show the categories that are in your shop on every page. You write a simple function that just returns a dictionary called menu categories, you load something from your database, and that's it. This means that in every template that is rendered, this variable will be available. You can refer to this menu structure in every template, and you can do that in your base template or in one of your snippets or in one of your places. when you want to do it. But it means you can't forget it, right? This is executed every time a template is rendered. Now middlewares are a little bit more complicated because they are more powerful. Let's look at the request cycle again.
Speaker 1: I was very happy that we did this workshop yesterday. I'm very happy that we that we could draw these things. So let's look at this request cycle again. Let's say I want to change how the template is rendered, or I want to change which view function is rendered, or I want to change which URL is dispatched. I cannot do this with any of the pieces that I've drawn here What I can do is that I can wrap it in the middleware and the middleware wraps the entire process. So a middleware is around the entire process and can hook into each of these things. It can hook into the dispatch, it can hook into the view function, it can hook into the context or and into the output. And it can even prevent them from doing these things.
Speaker 1: So here's an example from the Django Message Middleware. It doesn't matter what the code is. What matters is that, first of all, this is much more complicated than a context processor. It can do more things, so it's more complicated. And the second thing that's important is that it has these hooks. It has process request, it has process response, it has also process template, and it has a few other hooks that you can hook into. And these are direct correspondences to these things. Right, whenever a request comes in, your process request function will be called. Whenever a response is generated, your process response will be called. Whenever a context is generated, whenever anything happens, your middleware um uh will be um will be called with the with the appropriate hooks.
Speaker 1: All right Which means you have much more control over what's happening. So one little yeah, there are more hooks The question comes up where do you put custom context processes? It really depends. It really depends where you put them. Usually you will have an app That is like your core application. I've called this took in my uh in my example. I sometimes call this core. If it's something that applies to the entire project or if it's something that applies to the whole site, I will use my context, I will put my context processes here. And I'll just create a file called context processes here And just create this here. If it's something that's pertinent to the shop or if it's something that's pertinent to the
Speaker 1: products or to anything else, I'll try to put this into the appropriate app. It's not easy to find places for that. This is one of the soft parts of this topic. Where do you put them? It's not clear. Just make sure that you can find them again, right? Don't put them into a file called utilities or don't put them into a file called rendering or whatever. Put them into a file called context processes so you know what's in there. These are the context processes. Especially since context processes are just functions. So you won't be able to tell them apart in the code. All right. Middlewares are a bit more obvious, right, because they use a middleware mix-in usually. So it's not as important to call them, but just do it, right? Just put them into file called middleware.
Speaker 1: All right, now that we know what they do, when should you use which one? And I have a handful of examples here. Where I want to talk to you about where you should put them. So we talked about the menu structure, right? Menu structure is something that appears in every page. And that means you would put it into a context processor. Just put your menu structure into a processor that puts it into every template. Let's say you want uh to add content security policy headers. This is not something that applies to a template, this is something that applies to the entire request. So you would put this into a middleware. There are links to these middlewares. So this one is Django CSP. There are links on the slides and on the on the materials you can see on the talk description so you can see what
Speaker 1: um You can see examples and you can do this. So this would be a middleware. This applies to the whole context, to the whole request, even though it is part of the response, right? Even though It looks like it should be part of a template. This is uh this must go in the middleware because it applies to the entire request. Let's say you want to look at database queries. You want to look at your database query fan out Since this doesn't apply to the template, this isn't something that you would just show but yet that you would also detect, you would put this into a middleware. And there's a middleware called n plus one linked in the description Let's say you want to count database queries. There's also a middleware for that. Again, it
Speaker 1: doesn't apply simply to the template, it applies to the entire request. There's a middleware called Django query count um link in description. Let's say you want to put you want to show your shopping basket. You want to show the user what's in their current shopping basket Now this doesn't apply to the entire request. This is something that you just show, right? So you put it into a context processor. Most of these examples are simple examples, but um And you could do these in many different ways, but um these are my suggestions. Let's say you want to monitor login attempts. Now this is one of an interesting one of an interesting thing because there is a template response that shows when a login attempt has failed
Speaker 1: But that showing alone is not enough, right? You want to write something to the database. So you would put this into a middleware. There's actually um Middleware called Django Access by Jazz Band, Access written A X E S , link in the description, that you can use for that, and it'll just monitor every every attempt to log in and it'll show you failed attempts This is one of these things where at first you might think, yeah, I I just record the error message on the template. Um, but this goes further, so you have to wrap the entire request. Let's say you want to put course headers, cross-origin headers onto your request. By now it shouldn't be a surprise. This is a middleware it wraps the entire request. What do you do if you show the most recent blog posts on your page?
Speaker 1: Now you could put this into middleware. It would be easy to put this into middleware where on each request or every time a context is rendered, you just add the recent blog posts. But it's much simpler to do this in a context processor. And for this, for example, it would be easy to know which app should contain these, because these are about the blog posts. So this is where you um this is where you um Have your models, you'll just put your blog post. Okay, there are a few more. I am going to skip through them. We were a bit slow. Breadcrumbs. I have no idea how to do breadcrumbs. If you have a solution for breadcrumbs, please tell me.
Speaker 1: I have no idea how to do those. All right, um show items in a page footer. Um these are the things. All right. Um this is the picture that you have to keep in mind. If it's for a simple template that you want to render Put it into a context process. If it's for a request, put it in a middleware. Alright. I have prepared more stuff, but we're running out of time. We were a bit slow here. Let me just skip very quickly to the end. We can talk in the Jitsi about the about where you to put your code. You can also look at the recording. There's a pre-recorded view where I actually get to that. And you can look at that or we can talk about it That's all I have for today.
Speaker 1: But of course, there is more. Join me on Discord, join us on Telegram, talk to me on Jitsi, write me an email, look at the list on GitHub. There's a lot of stuff that can be done and there are a lot of challenges and there are people who can help with these challenges. Thank you for attending. I will be in the Jitsi. Let's talk about this and uh thanks for being here. So hello everyone. Sorry we couldn't get to the fourth part. But we can talk about it here if you want to. Well, there were more people in that talk than I had expected. Oh, I'm too loud. All right, any questions?
Speaker 1: Anything you want to talk about
Speaker 3: But uh listen about uh where to put your quotes. I think it's uh like a holy grail of Django or of every Django project and Every time you do that, there might be some wonderings.
Speaker 1: Yeah.
Speaker 3: What can you say about it? Thanks.
Speaker 1: Putting your code where you put your code is one of these one of these problems, right? It's one of these things that there's no answer. There's no th or or there are too many answers. Um what I have in my talk is the question should you put it into models or into views or into managers or somewhere else? And there is no clear answer where you should put this. Um I have some suggestions in this talk. You can look at the recording or and you can look on the slide at the slides if you want to. But there is no clear answer. There there are guidelines for these things. So so one of the one of the things that happen is that you have models that grow in size, right? This is one of the first things that you do um when you have models, you just put code in there. And they grow and grow and grow and grow.
Speaker 1: And so at some point they are massive, massive models. 400, 500, 1,000 lines long. And At that point, it's not clear what the model does anymore. And you have to think about what is the model. And in Django, the model is actually an abstraction over the database, the data that is stored in the database Now, if you look at the functions in your models, you have to decide is this part of the data that is stored, or is it adjacent to that? Like is it a computation on that data? Or is it something that happens entirely in another place? So you might have um a shopping basket model and then you might have a function where you check out from that shopping basket and create a charge on Stripe or on PayPal or whatever.
Speaker 1: Does that belong into the model? Well, yes and no, right? It it belongs to the data in the shopping basket, but it's not really part of that. It it it goes further than that. So the question is, should you put this into the model? And It's very intuitive to do this in the model at first. Um, but the it's not super super clear and super clean. And I think You follow the workshop, right? I try to to organize things that they are clear and clean. And having a hundred functions in your models isn't neither one of those. So yeah, one of the things you could do is you could do it into um the view function, but view functions aren't super easy to reuse So
Speaker 1: view functions, yeah, they're also kind of natural plays, but they're they're like for one-offs, right? For things that you only do once. Um My desired choice for this would be a model manager, which is the abstraction around the database, right? The abstraction around the table. So model. objects is the default manager that you get. And it's very easy to add more managers there. And you could add a charge manager that contains this function for doing for doing stripe charges. It's the problem is that this is a very soft topic, right? We could talk a whole day about this and we would still disagree. Um but does that give you some idea of what I think about this?
Speaker 3: Yes, thank you. And I will definitely look up uh slides and recording afterwards. Thank you.
Speaker 1: Excellent. Excellent. And if you have questions, join us on Discord or email me or on Telegram or wherever you can find me. All right. I am looking forward to hearing from you
Speaker 3: Sure, thank you.
Speaker 1: All right. There was another question.
Speaker 4: So I just wanted to ask that uh have you made any script or something to automate this task for you? Because you seem to be doing it. in every of your projects.
Speaker 1: One of the things is you could do a cookie cutter. Uh Django Cookie Cutter um or or Cookie Cutter is a project generator and you can have templates for that. And there's an excellent template. Um called Django Cookie Cutter. But that contains a lot of things that I don't use every time. It contains white noise and and a lot of like mail gun a lot of stuff that is good if you have large hosted sites. But I don't use them all the time. I uh every time I start a new project, I think about creating my own cookie cutter solution for that. I've I've never gotten around to do that. Um there's also uh Junko has a built-in templating system for projects. And every time I start a project, I think about doing that myself as well, but I haven't.
Speaker 1: So right now this is an entirely manual process, so you've just seen what I do in new projects. Sorry. At some point I try I will try to have this, but I don't try now. Alright. There's another one that that wants to talk. Please go on. AK wants to talk. And Andrew Kim. You're muted, so if you want to talk, you have to unmute yourself. Oh sorry, your microphone is not working. Yeah, yeah, it might.
Speaker 1: Might be a great topic for a sprint. Just um Um it might be a great topic for a sprint just to look at projects and try to reformat them, so to speak. or to or to create a new project or to create a cookie cutter or to create a template. That might be a nice topic for Sprint. Unfortunately, I can't join the Sprints this year, so we'll have to do it on some other some RRAs. Yeah. Yeah, we could we could put that into the sprints. All right. Uh Andrew Kim asks, would you ever just have one URL? I don't think I understand. What I do in in my in my central URL conf is that I wire up all the apps. Doesn't matter
Speaker 1: which What whether I intend to have URLs in there or not, I just wire up all the apps. That makes it easy for me to add URLs later on. Oh, thanks, Thomas. Um makes it easy to extend this. Now, if you have more than one URL for a thing, you have to think very hard about the names. You have to think very hard about what these things are called. But for me the important point isn't the number of URLs because the number will explode, right? You will have a hundred URLs in there in no time. The the thing that happens is that because you have so many URLs, it's hard to tie these together. It's hard to find the correct template for the view that you're looking at.
Speaker 1: And it's even harder if you're in a template to find the view that uh renders this template. Because they are not tied together by any code mechanism. They're They they're tied together by just one call from the template to there. But that might be very unobtrusive or it might be hidden, um, or it might be not visible. So so so the main point I'm trying to do is I'm trying to keep the names as close as possible together so I can navigate between them without having to inspect the code. Um Andrew, does that
Speaker 5: sorry. Yeah. My microphone's working now. I guess my original question was, would you ever have one URL dot py file file? Because, you know, if you for like view files, there's a lot of lines you have to write. But like for URL, it's actually quite condensed. So I'm just wondering, you know.
Speaker 1: Yeah.
Speaker 5: Would you recommend or would you not? Yeah.
Speaker 1: In in the apps, I have never had more than one URLs file. At some point I will split up my views into modules. So I will not have a views. py, but I will have a views module. And then under that I will have views for different uh things because as you say views are kind of they they expand right a view can easily have 50 lines or something like that and then it's not not as easy to organize them anymore but in the URLs. py I usually have one and Because they are structurally very easy, right? It's just a list from top to bottom and one line per entry. And then it's easy to scan through them. I haven't had it. I haven't had the need to split my URLs. But yeah, I could see when you have too many that you would want to split them. And then you just include them as
Speaker 1: as before. Um
Speaker 5: thank you, thanks.
Speaker 1: Yeah, you're welcome. So uh wait Wojcic um asks in the chat, sorry if I mangled your name, would you say it's better to have many smaller apps even if they're not ever going to be reused? Are there any caveats to watch for? And that is one of these brilliant question. Thank you for that question. It's an excellent question. And it's one that doesn't have an answer. It's impossible to answer this question. But I can tell you what I think. And when I started doing Django projects, all of my stuff was in one app, right? As you saw before, right? There was a project called Took, and everything was in the app called Took. Everything was in there. Because all the models reference each other, all the views reference each other, the URLs repeat and so on and so forth, right?
Speaker 1: So it's kind of natural to put all of that into one thing. But um when I did larger projects, I kind of did the opposite. I did everything into its own app. So there's something related to the shop module. Nice one I uh its own app called shop. There's something for the menu, nice everything to the menu. There's something belonging to users, user management, a nice users app. So I tend to do smaller apps nowadays. I tend to just decompose my application, my project into smaller apps so I have more of them. The the this makes it kinda easy to refer to these things by their place, right? So if you have if you have an app called
Speaker 1: users If anything uh happens to users, it's in that app. If if anything needs to be done with users, if you need to show a profile or registration or whatever, um that's gonna be in the users app. But that makes problems as well, and there are the caveats. Um you cannot easily have circular dependencies anymore If you split things up into apps, you must have an order for the apps. Because while you can refer from one app to the other, you cannot have cycles. Right. You cannot refer from the shop app to the users app and from the users app to the I don't know menu app and from the menu app from to the um to the shop app because then Django cannot import this triangle anymore.
Speaker 1: You must have a clear dependency tree. It must not have any cycles. It cannot have any cycles, otherwise, it will be impossible to import. And that is the main caveat here. So if you structure your apps too finely. You will not be able to do the the the imports. You cannot be able to refer back up to the tree. And that's that's the thing. And that's the main point. where I hate doing the doing the apps and where I sometimes merge apps because they just have to refer to each other. All right. You can kind of work around this with with delayed imports, but it's that's not nice. Does that answer your question? I'll I'll take your Muteness as yes. Nice.
Speaker 1: Thanks. All right. Nigel Finch, that's a name I can I can say. Asks for multi-tenancy projects, do you build the logic into the views or is there a go-to multi-tenancy package that you use? I try to avoid multi-tenancy. In one of the projects that we did, I actually went so far as to have deployment infrastructure for the same project multiple times because we used it in multiple projects. I try to avoid that. And that means I don't have a package ready for that. I don't I don't do that, so I don't I can't I can't help you there, sorry. But someone on the Django Unstack Discord probably will have that problem and uh join us there and we'll talk about this in the larger circle, not just me. Sorry for not having a better answer for your question, Nigel.
Speaker 1: Cheers, thanks. All right, anything else we should talk about? Does anyone have any ideas how to do breadcrumbs in pages? Because I certainly don't. All right. No ideas, no questions? Then I think we're done here. Thank you again very much for joining me in my talk. Thank you again very much for your questions and for your discussions. And if you have more topics, join me on Discord, join me on Telegram, send me an email. I'm happy to hear from every one of you. I'm also in the Slack. I will be in the Slack for today and tomorrow. Send me a message and we'll talk. Thanks everyone. Bye bye.
Speaker 5: Thank you. Thanks.
Speaker 4: Top was really useful really useful.
Speaker 1: Yeah, thank you very much. I'm glad it helps.
Put project configuration in a clearly named `config` package, split settings into a shared `base.py` plus environment-specific development, test, and production files, and keep applications in an `apps` directory. Add the apps directory to Python’s path so apps can retain simple import names.
Discussed at 7:31Give every app its own `urls.py` and include each app’s URLs in the project URL configuration as soon as the app is created. This keeps app URLs local and avoids having to integrate them later.
Discussed at 17:38Create a project-level `templates` directory and add it to the template setting’s `DIRS`; it is searched before other template directories. Use it for project-wide base templates, snippets such as menus and pagination, and overrides for built-in templates such as login pages.
Discussed at 21:47Create `app/templates/app/` and put the app’s templates inside that namespaced directory. The repeated app name prevents template-name collisions and makes it clear which app owns a template.
Discussed at 27:12When practical, use the same name for the URL pattern, view function, and template file—for example, `main` and `main.html`. This ties the three pieces together and makes navigating between them easier; the same namespacing principle should also be applied to static files.
Discussed at 35:09A context processor adds values to the template context every time a template is rendered, making it suitable for page-wide data such as menus or the logged-in user. Middleware wraps the request/response cycle and can hook into or alter requests, views, templates, and responses, so it is more powerful and complex.
Discussed at 38:46Put project-wide context processors in a core app, and app-specific ones in the relevant app, in a clearly named `context_processors.py` file. Put middleware in a clearly named `middleware.py` file so its purpose and location remain easy to find.
Discussed at 42:12Use a context processor for data that is displayed in templates, such as menu categories or a shopping basket. Use middleware for behavior affecting the whole request or response, such as security headers, database-query monitoring, query counting, or login-attempt monitoring.
Discussed at 43:46Note: We understand that names change, people change, and bodies change. We respect each individual's journey and privacy. If you have any concerns about a video or need us to remove content, please don't hesitate to contact us. We will handle your request with care and promptly address any issues.
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025
Published June 13, 2025