To create URL patterns for specific pages we can use the following argument to our path function to avoid hard-coding a specific route:

path("blogs/<int:blog_id>/", blog, name="blog")

Caution

Note the trailing ”/“. Default URL matching takes it into account!

What this does is make Django match URLs in the form of <base URL>/blogs/<int>/. When the pattern is matched, the request is sent to the blog function, along with two arguments: request and blog_id. As a result, we can update the blog view function as follows:

def blog(request, blog_id):
	blog = Blog.objects.get(id=blog_id)
	posts = blog.blogpost_set.all()
 
	context = {
		"blog" : blog,
		"posts" : posts,
	}
	return render(request, "blog.html", context)

Note the inclusion of the context variable, which is required to make Django Templates have access to data.

Info

When doing real-world deployments it is generally worth while to use UUIDs rather than simply incrementing the ID values in the URL to avoid information leakage.

An important part of passing the context properly is to be able to dynamically generate links in pages using Django Templates. Consider the following, for example:

{% extends "base.html" %}
 
{% block content %}
 
  <h2>Blogs</h2>
 
  {% for blog in blogs %}
 
    <div class="card">
      <header><h3>{{ blog.title }}</h3></header>
      <p>{{ blog.description }}</p>
    </div>
 
  {% empty %}
    <h3>No blogs have been added yet.</h3>
  {% endfor %}
 
{% endblock content %}

In this code we don’t have href links to the specific blogs. An option would be to hard code or have users manually enter the specific blog IDs for each individual blog, but that seems like a terrible idea. Instead, we can do the following:

<div class="card">
  <header>
    <h3>
      <a href="{% url 'blog' blog.id %}">{{ blog.title }}</a>
    </h3>
  </header>
  <p>{{ blog.description }}</p>
</div>

Here the important line is "{% url 'blog' blog.id %}". This is a simple url_for function used before, but we include the extra parameter blog.id (which is available through the view context) in order to pass it to the view function call.