Learn / Frameworks / Django / Views, URLs and Templates

Beginner 17 min

Views, URLs and Templates

Route a URL to a view and render HTML with the template language.

What you will learn

  • Write function views
  • Map URLs
  • Use template tags and filters

When a browser asks for a page, Django looks up the URL in your URL configuration, calls the matching view, and sends back the response the view returns.

# blog/views.py
from django.shortcuts import render, get_object_or_404
from .models import Post

def post_list(request):
    posts = Post.objects.filter(published=True).select_related("author")
    return render(request, "blog/post_list.html", {"posts": posts})

def post_detail(request, pk):
    post = get_object_or_404(Post, pk=pk, published=True)
    return render(request, "blog/post_detail.html", {"post": post})

render combines a template with a context dictionary. get_object_or_404 returns the object or an HTTP 404 page, instead of crashing with an exception.

# blog/urls.py
from django.urls import path
from . import views

app_name = "blog"
urlpatterns = [
    path("", views.post_list, name="list"),
    path("<int:pk>/", views.post_detail, name="detail"),
]

# mysite/urls.py
from django.urls import include, path
urlpatterns = [
    path("blog/", include("blog.urls")),
]

<int:pk> captures a number from the URL and passes it to the view as pk. Giving each route a name lets you generate links without hard-coding paths.

Templates

Create blog/templates/blog/post_list.html. Templates use {{ variable }} to print values and {% tag %} for logic.

<!-- blog/templates/blog/post_list.html -->
{% extends "base.html" %}
{% block content %}
  <h1>Posts</h1>
  {% for post in posts %}
    <article>
      <h2><a href="{% url 'blog:detail' post.pk %}">{{ post.title }}</a></h2>
      <p>by {{ post.author.name }} on {{ post.created|date:"M d, Y" }}</p>
      <p>{{ post.body|truncatewords:30 }}</p>
    </article>
  {% empty %}
    <p>No posts yet.</p>
  {% endfor %}
{% endblock %}
  • {% extends %} and {% block %}: inherit a shared layout so you write headers and footers once.
  • |date, |truncatewords: filters that transform values.
  • Django auto-escapes variables, protecting against XSS. Only use |safe on content you fully trust.

Class-based views

For common patterns, generic views remove boilerplate.

from django.views.generic import ListView, DetailView

class PostList(ListView):
    model = Post
    queryset = Post.objects.filter(published=True)
    template_name = "blog/post_list.html"
    context_object_name = "posts"
    paginate_by = 10
Common error

TemplateDoesNotExist usually means the folder is misnamed or the app is missing from INSTALLED_APPS. Templates conventionally live in app/templates/app/.

Try it yourself

Add a page at /blog/about/ that shows the number of published posts using a view, a URL and a template.

Show solution
# views.py
def about(request):
    return render(request, "blog/about.html", {"count": Post.objects.filter(published=True).count()})
# urls.py
path("about/", views.about, name="about"),
# about.html
# <p>We have {{ count }} posts.</p>