Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Variable Arguments From URLs: Routing and Views

In the previous lesson, you learned how to pull one specific resource out of your database. Now you need to build that code into your views and set up the correct routing so that you’ll be able to see the details page of one of your projects.

In urlpatterns in your projects app, you had an empty path that just went to projects without anything afterwards and then rendered your all_projects view. Now, you need to add a second path:

Language: Python
urlpatterns = [
    path('', views.all_projects),
    path('<int:pk>', views.project_detail)
]

You can use the characters < and > to captures a part of a URL and pass it forward into your app.

00:00 In the previous video, we learned how to pull one specific resource out of our database. Now, we want to build that code into our views and set up the correct routing so that we’re able to see this details view of one of our projects.

00:17 Over here in the urlpatterns of our projects app—remember, we have this empty path that just goes to /projects/ without anything afterwards—and then renders our all_projects() view, which lists all the projects that we have.

00:33 Now, we want to add a second path() in here.

00:38 This might look a bit weird at the beginning, but just take a look. We’re going to talk over what’s going on, okay?

00:55 All right. So, PyCharm’s complaining, project_detail—this view doesn’t exist yet. We already know what that’s going to bring us, it’s going to bring us a little error, but we can build this view.

01:07 We did it before and we’re going to do it again, but the interesting part for us now is this part here.

01:15 So, that looks weird, right? We don’t have just some text in there, but we have these angled brackets. We have a : in there. int looks familiar, could be integer, right? pk—we just talked about that before.

01:25 Maybe it’s the primary key. But what exactly is going on in here? Let’s take a look at this on some slides! So, what we want to do with these angled brackets is we want to use them to capture parts of the URL.

01:40 So, you can imagine this little cowboy emoji that has this lasso with these angled brackets. It uses it to fetch stuff from the URL and pass it forward into our app.

01:51 So, what you can see here is essentially what—in the demo, before—I typed into the browser bar up top, right? We were on /projects/, and then we could just type the different numbers—in this case, 1and then it brought us to this details page.

02:07 What’s happening here is that our cowboy emoji lassos the rest of the URL—the number, in this case—with the angled brackets, and then flips it up there and passes it on to our view, whatever we defined here—in this case, project_detail().

02:26 Remember that how it’s passing it forward—in that case, that’s defined over here. We’re giving it a variable named pk, which just stands for primary key.

02:36 But this is going to be available inside of project_detail()—in this view function—under the variable pk, okay? That’s important to remember for us to then build out the view that we need to correctly render this details page. All right, so with this, we explained the angled brackets here and this pk, right?

02:57 But what’s this int and the : here? This part is called the path converter. There’s different ones. In this case, we’re using the int one with a :.

03:08 That’s a path converter. What our integer path converter does is it makes sure that what gets entered here at the end is actually an integer. Otherwise, it gives us an error.

03:18 So it avoids that some funny guy would come in here and—instead of just giving a number at the end—type some funny URL, right? This is just not going to work because the path converter checks whether this is an integer—what gets cut off here, the rest of this. And if it isn’t, then it just says, “Okay, I’m not passing this forward.” This avoids that we would run into an error later, because we need the primary key to be an integer to correctly query our database. We wouldn’t find anything here.

03:51 This catches it early and just tells us, “Nope, this is not going to work.” And something like this comes in, a 1, then this can be converted to an integer, and it’s going to give it a go-ahead and pass 1 forward to project_detail(), to the function. Inside of the function, then, we’re going to use it to query our database for this very specific entry that we’re looking for. Next, let’s head over to views and build out the code logic that we’ve just been talking about. So, heading over to views, we now want to create a second view function.

04:30 We have all_projects() here, and here, our error friend is already complaining that 'project_detail' doesn’t exist, so that’s what we’re going to build next.

04:41 project_detail() takes a request as an input. Then now, we’re at an interesting stage because it’s also going to take a primary key as an input.

04:51 It’s going to take an integer as an input that gets sent over by our URL resolver. So this part here, as you remember, the little cowboy catches it and passes it on to project_detail().

05:05 So, it’s coming in here as a second argument.

05:10 Okay. And that means we can use it, right? We want to query for one Project, so I’m going to say project = Project.objects.get(), and this code looks familiar because it’s exactly what we’ve been using inside of the Django shell, before, to query our database.

05:29 We’re doing the exact same thing and we’re giving it, here, the number that comes from the URL. So if a user puts in a 1, it’s going to pass forward the 1 here and query our database for the first entry. If it’s a 2, for the second one, et cetera.

05:46 Cool! Then, all we need to do is return this. We’re going to want to render a template again.

06:03 And again, we’ll need to pass this context dictionary in here, and here, I’ll just call it 'project' because we’re only passing one Project.

06:14 We hand it forward in the same way that we handed the list of projects forward before. All right. This finishes up our view function. Let’s go over it quickly again.

06:26 We’re defining project_detail(). We’re passing in the request—as always, in Django. In this case, what differentiates it from the other one before is from our urls file, we’re getting the information that it cuts off from the URL and passes forward to project_detail(). We’re catching it here, and then we’re using it in order to be able to query our database, to get a very specific Project back from it.

06:53 The rest is the same as above: we’re redirecting forward to a template and we’re passing this project, the Project object that we pulled out of the database so that we can then later render it in our template. Let’s look at this in an overview.

07:15 Here we go. Inside of our browser, someone enters this /projects/1, for example. This part gets snipped off by the path()—by using these angular brackets,

07:29 it cuts it off. It checks: is it an integer? In this case, yes. And passes it forward under this variable name to our new view function. In there, we use it to query the database and finally return the object that we got from there and pass it forward to the template.

07:47 And remember, yeah, the one who’s doing this using the angled bracket lasso is our cowboy emoji. All right. So, is that it? Can we now access a single resource? Let’s give it a try.

08:01 I’m here at our page. We wanted to try, “Can I access the first resource if I type this in there?” All right! We’re getting somewhere. We’re getting a familiar error, it’s telling us TemplateDoesNotExist. Right. We said, “Forward to detail.html,” but we don’t have this template yet. So let’s go ahead, follow Django’s tip, and build out this template.

08:42 Okay. So, I have this basic structure again. Inside of the body I’m just going to try to print out if this—can we access our Project object?

08:54 Let’s take a look.

08:58 And there it is! Perfect. So, it’s working. And now, if I go to the second one, there we are. We’re finding the second Project object. I’m going to make this a bit more readable real quick, but this is already a success for us.

09:37 So, let’s use this also to revisit how we can display an image from a static file. We need an img tag here that links to a static tag,

09:50 static, and then give the URL here: project.image. That’s the path that actually finds its way in here to our image file, the associated one with this project.

10:06 And here, we can give in the .description.

10:13 And what else we need to do is at the beginning of the template, we need to {% load static %}.

10:24 Okay? Now, when I head over here and reload, we can also see the image. We have the image, we have the title, the description. We can also add the technology. Let’s finish it up.

10:47 And now, we have all the information from our database displayed here on the details page. I’m now on number 2, but I can easily switch to number 1 and I get all the different information here. All right, great! With this code, we built out the functionality to actually display a single resource.

11:06 We already picked out some of the information that we want to display from the database. In the next video, we’re going to take a look how to link this

11:17 from this standard page so that we can then click, actually, instead of having to type in the URL ourselves up here. See you there.

Avatar image for Martin Breuss

Martin Breuss RP Team on May 26, 2020

Hi @vivekdeo you’ve stumbled across a subtle typo: one superfluous "s"!

In your view function you’re passing the data on to your template with the key name projects. This key name is how you will be able to access it in your template. However, in your template you are trying to access the data via the key project (without the s at the end).

So you just need to keep in mind that the key in your context dictionary and the variable name that you use to access the data under in your template match up.

Avatar image for tomislavm021

tomislavm021 on Aug. 5, 2020

What if you have more registered users, who want to add stuff in their app?

How would you filter those results so only users who created them, can see them?

I am trying with .filter but i can not get it to work :(

Avatar image for charneuk

charneuk on Aug. 11, 2020

When I load 127.0.0.1/8000/projects/1, I get a blank screen.

Avatar image for charneuk

charneuk on Aug. 11, 2020

NM. I was using {'projects':project} in the views.py file. Changed it to project. Now it works.

Avatar image for David K

David K on March 31, 2021

Proofreading assist :) Slide Page 245 of PDF (and your video), refers to projects rather than the singular project in the reference passed into the detail view.

The video of the coding process is correct, but the slides shown (and the PDF) is incorrect. Just in case someone was following the slides…

Avatar image for David K

David K on March 31, 2021

Slide content pp 245

return render(request,"projects/detail.html", {"projects": project})

should be

return render(request,"projects/detail.html", {"project": project})

Avatar image for Martin Breuss

Martin Breuss RP Team on March 31, 2021

Hi @davidcfk. Yes, that’s a typo! There are some comments further up clarifying that already, but thanks for bringing it up again to have it at the bottom of the comments, too. :)

Avatar image for David K

David K on April 2, 2021

Funny that - I really wish there was a delete function on these comments, I realised it was mentioned afterwards :) Thanks for a good overview on Django :)

Avatar image for mochibeepboop

mochibeepboop on Sept. 10, 2023

What a great course! Quick question, why do we need {"project": project} in views.py? Why append the project as a value of a dictionary key? What accesses this value?

def project_detail(request, pk):
    project = Project.objects.get(pk=pk)
    return render(request, "projects/detail.html", {"project": project})

Thanks!

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Sept. 11, 2023

@mochibeepboop render() is a shortcut function provided by Django, which expects a dictionary as an optional third parameter. It’s called the context of your template, and it’s a standard way of passing named variables into the template, letting you interpolate an expression like this:

<h1>Project name: {{ project.name }}</h1>

Other frameworks, such as Flask, use a similar pattern, but instead of expecting a dictionary, they let you pass a variable number of arguments (*args):

@app.route("/project/details/<pk:int>")
def project_details(pk):
    project = Project.objects.get(pk=pk)
    return render_template("project_details.html", project=project)

Ultimately, the idea is the same in both web frameworks.

Become a Member to join the conversation.