In this lesson, you’ll learn about linking templates together, namespaces in Django, path names, and passing arguments in URLs. You’ll also make friends with a new error: NoReverseMatch!
Join us and get access to thousands of tutorials and a community of expert Pythonistas.
This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.
URL Linking: app_name, Path Names, and Arguments
00:00
In this video, we’ll talk about linking templates together, we’ll talk about namespaces in Django, what’s the app_name, how do you assign path names, and also how to pass arguments around in your URLs.
00:14 So, the a first thing we want to do is we want to try to link two templates. Let’s take a look.
00:21 In our finished project, we have this list view where we can see all of the projects listed in our database. We have this button where we can click to get to the detail view.
00:33 Now in the project so far, we’ve implemented this detail view—we can go here and access it. However, we have this button there, and when we press the button, it currently doesn’t do anything.
00:44
That’s what we want to fix here. We want to go into this all_projects template and change something inside of the HTML that we have there in order to make this button working.
00:57
I’m here in all_projects.html, and this is the button that we looked at just before. In here is where we have to put the URL to link forward. Now, this shouldn’t be just a static URL.
01:09
We don’t want to hardcode it, because it’s supposed to be different for each project that we’re putting in there, right? So, what can we put in here? Django has this url tag.
01:20 It’s a Django template tag that looks like this, and then something follows after here. I’m going to run it, for now, like this. We keep it empty because that’s the piece that we’re going to talk about a lot more. But at first, let’s see what happens when we run it like this.
01:39 I’m clicking the button now.
01:44
I’m going to reload the /projects/ page. And what we get now is a NoReverseMatch error. It’s telling us that the Reverse for—and this maybe looks like a double quote, but it’s actually two single quotes. You can see it down here.
01:58
So, we have two single quotes, which is just what I put—if you remember, I put url and then these two single quotes. That’s just what it’s telling us here, that it couldn’t find a reverse for an empty string, essentially.
02:14 That it’s not a valid view function or a pattern name. We are going to focus on this pattern name. We’re going to figure out how to assign pattern names and how to deal with namespaces in Django in general.
02:25
And yes, NoReverseMatch is our new friend here, and I’m going to take this error as an example to dive a bit deeper into debugging errors, because it’s an error that comes up a lot and we want to practice some ways of like, “Where can we look?
02:39 How can we dig down and how can we figure out how to solve this error?” The first thing that we want to do is we want to deal with the missing pattern name.
02:48 We want to figure out what that is all about. And for that, we want to give names to patterns. The path that we just recently built, looked like this. Let’s take a look at what are the different names that we can give, that we can assign here to create a proper namespace.
03:03
So, here’s the path that we just recently built, and let’s take a look at how can we correctly link to this path coming from our template? I started off making this url tag and then left this part here empty.
03:15
Now, what we can see here is it says 'app_name:name' and then we also have this other part here: the argument that we’re going to talk about later. First, we’re going to make a functioning one just with these two parts.
03:27 We’re going to talk about that because this is the namespace that helps us to directly get to the specific view that we’re pointing to. Our task now is to give a name to the patterns in here so that we’ll be able to address it like this inside of the URL.
03:45
The first thing we need to do, inside of urls.py we have to define the app_name variable. That’s just how it’s called. We give it the name of our app—in this case, "projects".
03:57
And this is what’s going to come over here inside of the URL string, defining it. So, that’s the name of the app. First, the app_name, and second, we’re going to need the name of the path, and we can add this as a keyword argument inside of the path(), which is simply name= and then we can give it any kind of name that we want to. Generally, I try to keep it the same as the view that this is pointing to. And, as you might guess, we’re going to pop that name over here. So we have url, app_name, :, and then the name of the path() that we’re directing to.
04:35 This uniquely identifies a Django view. That’s the namespace for our Django view, and if we put this into the URL, it’s going to know where to direct us to. Okay, let’s go ahead and fix that in our project and then see what happens next.
04:51
First step, we said, we have to go to urls.py, and we have to add an app_name.
05:05 I’m naming this the same as our app, okay? Next, we want to add names to our paths.
05:27
And with these two features, the name and the app_name, you can uniquely identify the views that we’re pointing to. So over here, in all_projects.html, I want to now point to app_name, 'projects', and path() name, project_detail.
05:49
That’s what I named it over here—'project_detail' and app_name, 'projects'.
05:59 Okay, so this should create a proper namespace and uniquely identify the view. Let’s give it a try if we can—oh. We can also see the server started again, so let’s give it a try whether everything is fine and whether we can use the button to get to the details page. All right.
06:19
So, after the reloading this I got, again, a reverse match error. I got another NoReverseMatch error, but it is a different one. If you look here, it’s telling us not anymore that there is no valid pattern name or view function, but it tells us the reverse for 'project_detail' with no arguments was not found.
06:38
This is the important part here. It did find a reverse for 'project_detail', but not one that doesn’t require arguments. And then there’s some regular expressions here, some patterns that it tried.
06:51 It’s also pointing us to where the problem sits, down here. Always take a quick look at these error messages. They’re very useful. So, what we need to do is we need to pass an argument forward in order to be able to retrieve the right URL.
07:05
We’re looking for a URL that has the / and then the primary key of the resource that we want to get, and we need to be able to pass that forward.
07:16
The way to do this is that inside of the template, additionally to the namespace consisting of app_name and the name of the path, separated by a space, we can put in a number, essentially, here.
07:29 We’re going to want that to be a different number, depending on what’s the resource that we want to access, but essentially it just has to be some kind of argument that gets passed forward to the function. Let’s take a look at this.
07:42
If I would go in here, make a space and then just put a 1 here, for example, so I’m passing the number 1 every time. Let’s take a look at the effect that this has on our app.
07:55
I can reload. There’s no errors coming up. And now when I press, this button—yay! We’re getting to a details view. The details view number 1, which is correct for this one. What happens when I press this one? All right.
08:08
So, I get redirected again to the number 1, because simply every time this URL—this button—gets clicked, we’re just passing 1 forward. That’s not exactly what we want, but we’re getting close, right?
08:24
To explain this again, this is the thing. Whatever comes in here is getting passed on to the browser to create the URL, and this is the URL that it’s going to retrieve and pass forward to the view function, which then decides based on that, which Project to grab from the database and what to render.
08:42
To make this functional in the way that we were thinking about it, I’m going to change this to project.pk, which—again—is the same as project.id, in our case.
08:55
And this is just going to be 1 for the first project, 2 for the second project, et cetera. So now, we’re passing in this number—that is relative to the project that we’re looking at—into the URL resolver here, so that then, it’s going to direct us forward to the appropriate details page.
09:18
Clicking on project number 1 takes me to the URL /1, and clicking on the project number 2 takes me to the URL /2, which is the details page of our second entry in the database.
09:32
Good job! That’s what we wanted to achieve, and now our functionality here already mirrors the functionality of our finished app! So, remember to thank NoReverseMatch for that, because it’s really an error you might be encountering very often.
09:47
In the next video, we’re going to take a look at what are the places to look at and how to properly debug when you see a NoReverseMatch error.
Martin Breuss RP Team on June 11, 2020
Totally on the right track, only the syntax for this is a little different. Instead of a . to separate app_name and name, you need to use a :. :)
Martin Breuss RP Team on June 11, 2020
That rendered potentially a bit confusing with the colon-dot-smiley, so here’s the correct syntax:
'app_name:name'
Martin Breuss RP Team on June 11, 2020
Also keep in mind that this is not a reference to views.py, as you were trying to establish, it seems.
You are exclusively building these URLs through the information inside of urls.py, which is why all you need to construct the URL properly is the 'app_name:name' - both of which are located in urls.py.
Hope that helps to clarify this!
Bill Lafferty on June 11, 2020
Makes sense, thank you! Noted that it’s not in reference to views.
However, it is still giving me trouble. This gives me the same noreversematch error at /farmapp error.
<a href="{% url 'farmapp:produce_detail' project.pk %}" class="btn btn-primary">
Martin Breuss RP Team on June 12, 2020
This link should be fine now, you fixed it up correctly. There might be another link in that template that doesn’t have the correct namespace set up? If there is any link on your page that Django can’t resolve, it will give you the NoReverseMatch error.
Another thing I notice: you mention your template sits in template/all.html instead of templates/all.html (note the “s”). Django only automatically discovers folders in apps that are named “templates”. Might be a typo, but thought I’d mention it.
If none of this solves it you can post a link to your GitHub repo and I can take a look.
Sergey on Sept. 21, 2021
Hello!
I have a question about this url’s linking…
`<a href="{% url 'projects:project_detail' project.pk %}" `
Ok, this is right way to link another url. But… First thing that i did, after defining a function with a ‘pk’:
<a href="{{ project.pk }}"
And this solution also works fine. I think there is a good reason for more complex code. Maybe somebody can explain?
Martin Breuss RP Team on Sept. 23, 2021
Hi @Sergey, great question and kudos for playing around with the code 🙌 :)
One thing to keep in mind is that Django always resolves any code you write into HTML. So what you’re writing into the href attribute will boil down to strings that this HTML attribute can interpret.
Let’s look at what the two different Django code snippets you posted produce after being rendered (Note: you can do that by inspecting your page source):
href="{% url 'projects:project_detail' project.pk %}"will resolve tohref="/projects/1/"for the project withpk=1.href="{{ project.pk }}"will resolve tohref="1"for the project withpk=1.
Like you said, in the context of this project both will work and bring you to the detail page of that project. Both are relative paths, however, there is a difference:
- /projects/1/ will look at the root of your project and go from there
- 1 will look from where the current template is located
What do you think is the advantage of using one over the other? What happens if you try to use the shorter link to link from another Django app, e.g. the blog app?
Sergey on Sept. 23, 2021
Hello, @Martin!
Thank you for detailed answer, now i even more appreciate this course and Real Python.
Note: you can do that by inspecting your page source
This is a really great suggestion! And such simple!
What happens if you try to use the shorter link to link from another Django app, e.g. the blog app?
I think in best case scenario this will link button to some 404 Not Found…
Many thanks for you work, RP Team! Great course, great resource.
Calvin on Jan. 17, 2023
If anyone was following along and didn’t catch why you’re still getting NoReverseMatch/namespace issues, you will need to register the app_name in your urls.py file.
e.g.
from django.urls import path # remove include in this app...
from projects import views
app_name = 'projects'
# add app routes here
urlpatterns = [
path('', views.all_projects),
path('<int:pk>', views.project_detail, name="project_detail"),
]
Make sure to test and verify.
Become a Member to join the conversation.
Bill Lafferty on June 11, 2020
Hi Martin,
Ok, to add the
app_name, I think I need to do as follows. Still not working, though. Am I on the right track?