Django Views and Templates: From Logic to Display

Written by Fabien Schlegel

Fabien Schlegel

5 min

published: 12/30/2025

Django Views and Templates: From Logic to Display

If models and ORM are the brain of your Django application, views and templates are its heart and face. It is the collaboration between these two pillars that transforms your application’s logic into interactive web pages that your users can see and use.

In Django’s MVT (Model-View-Template) architecture:

  • The Model handles the data.
  • The View handles the logic (what to do with the data).
  • The Template handles the presentation (how to display the data).

What is a Django view?

A Django view is a Python function (or class) that has a very clear responsibility: receive a web request and return a web response.

Between these two moments, the view executes the necessary business logic: it can interact with the database via models, process data, validate a form, etc.

The response can be simple (text, a 404 code) or complex (a full HTML page, a JSON file).

Function-Based Views (FBV)

The simplest way to create a view is to use a function. This is called a Function-Based View (FBV).

Each FBV takes at least one argument: request, an object that contains all the information about the user’s request.

Here is the simplest possible view:

# in your application's views.py file
from django.http import HttpResponse

def simple_hello(request):
    return HttpResponse("Hello, world!")

To make this view accessible, you must link it to a URL. In your application’s urls.py file:

from django.urls import path
from . import views

urlpatterns = [
    path('hello/', views.simple_hello, name='hello'),
]

Now, if you visit the URL /hello/, you will see the message “Hello, world!”.

Class-Based Views (CBV)

Class-Based Views (CBV) are an alternative to FBVs. They allow code organization as Python classes, which promotes reuse and structure for common patterns.

Rather than writing a function for each view, you define a class that inherits from one of the generic views provided by Django. These generic views are designed for frequent use cases:

  • ListView: To display a list of objects.
  • DetailView: To display the detail page of a specific object.
  • CreateView, UpdateView, DeleteView: To handle creation, modification, and deletion forms.

Let’s take the example of our article list page. Instead of the FBV seen above, we can use the ListView:

from django.views.generic import ListView
from .models import Post

class PostListView(ListView):
    model = Post
    queryset = Post.objects.filter(is_published=True)

The code is more concise. You just need to specify the model (Post) and optionally filter the queryset. The generic ListView takes care of the rest: retrieving objects, passing them to the template, and rendering everything.

By default, Django looks for a template named post_list.html and injects the list of objects into a variable post_list.

In urls.py, the syntax is slightly different: we call the .as_view() class method.

path('posts/', views.PostListView.as_view(), name='post-list'),

The power of the Django Template Language (DTL)

Displaying raw text is fine, but websites are made of HTML. This is where templates come in. A Django template is an HTML file enriched with a special syntax, the Django Template Language (DTL), which allows displaying data dynamically and using simple presentation logic.

To render a template, we use the render() shortcut. It takes the request, the template filename, and a “context” dictionary containing the data to pass to the template.

from django.shortcuts import render
from .models import Post
import datetime

def post_list(request):
    posts = Post.objects.filter(is_published=True)
    context = {
        'post_list': posts,
        'current_time': datetime.datetime.now(),
    }
    return render(request, 'blog/post_list.html', context)

The post_list.html template could look like this:

<h2>Our latest articles</h2>

<p>It is currently {{ current_time }}.</p>

{% if post_list %}
<ul>
  {% for post in post_list %}
  <li><a href="">{{ post.title }}</a></li>
  {% endfor %}
</ul>
{% else %}
<p>No articles to display for the moment.</p>
{% endif %}

This special syntax is the DTL:

  • Variables ({{ ... }}): Display the value of a variable passed in the context. You can access object attributes with the . notation (e.g., post.title).
  • Tags ({% ... %}): Execute programming logic. The most common are {% if %} / {% else %} / {% endif %} for conditions and {% for %} / {% endfor %} for loops.
  • Filters (|): Modify the display of a variable. For example, {{ current_time|date:"d F Y" }} would format the date in a readable way, or {{ post_list|length }} would display the number of articles.

Template Inheritance: The DRY Principle

To avoid repeating the same HTML code (like <head>, <body>, the navbar, the footer) on every page, the DTL uses a powerful inheritance system.

  1. Create a base template (base.html) with the common structure and empty “blocks”.
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
  <head>
    <title>{% block title %}My Super Blog{% endblock %}</title>
  </head>
  <body>
    <nav>
      <!-- Common navigation bar -->
    </nav>
    <main>{% block content %}{% endblock %}</main>
    <footer>
      <!-- Common footer -->
    </footer>
  </body>
</html>
  1. Create a child template that “extends” the base template and fills the blocks.
<!-- blog/templates/blog/post_list.html -->
{% extends "base.html" %} {% block title %}Our Articles - My Super Blog{%
endblock %} {% block content %}
<h2>Our latest articles</h2>
<!-- ... the rest of your article list code ... -->
{% endblock %}

Django will merge the two at render time to create a complete HTML page.

FBV vs CBV: Which one to choose?

Here are some guidelines to know which approach to use:

  • FBV (Function-Based Views):

    • Pros: Very explicit, easy to read and understand. The code flow is linear.
    • Cons: Can lead to a lot of repetitive code for standard operations (CRUD).
    • Ideal for: Complex and unique logic that doesn’t fit any standard pattern.
  • CBV (Class-Based Views):

    • Pros: Extremely efficient for common patterns (CRUD). Promotes the DRY (“Don’t Repeat Yourself”) principle by encapsulating and reusing logic.
    • Cons: Can seem “magical”. The code is more abstract, and you sometimes have to check the documentation to understand everything the generic view does in the background.
    • Ideal for: CRUD operations and pages that follow a classic structure (lists, details).

In summary: start with FBVs if you are a beginner to fully understand the request/response flow. Once comfortable, use generic CBVs to speed up your development on repetitive tasks.

Conclusion

Views and templates are the linchpin of what the user sees.

  • The view is the conductor: it receives the request, talks to models to get data, and decides which “score” (template) to play.
  • The template is the musician: it receives data and instructions from the view and takes care of presenting them nicely to the user, following the structure defined by inheritance.

Related Articles