Hello! In our last lesson, we covered the core building blocks of a Django app: Models, Forms, and the basic idea of Views. Now, we're going to explore the more advanced, powerful features that make Django so efficient for building complex applications.
This lesson is all about reusability and customization. We'll dive deeper into Class-Based Views (CBVs), see how Mixins supercharge them, explore the "magic" of Signals, understand the request-response lifecycle with Middleware, and learn how to write our own custom Template helpers.
In Django, a view is logic that takes a web request and returns a web response. We can write this logic as either a simple function (Function-Based View, or FBV) or as a class (Class-Based View, or CBV).
A Class-Based View (CBV) is a Python class that inherits from one of Django's built-in `View` classes. Instead of a single function, it provides different methods (like `.get()`, `.post()`) to handle different HTTP requests.
Analogy: The Restaurant Menu
# Example of a generic CBV
# This one class handles all the logic for
# showing a list of all products.
from django.views.generic import ListView
from .models import Product
class ProductListView(ListView):
model = Product
template_name = 'products/product_list.html'
context_object_name = 'products'
A mixin is a special kind of Python class that provides a "bundle" of extra functionality to another class. It's a way to "mix in" features without using complex inheritance.
In Django, mixins are power-ups for your Class-Based Views.
Analogy: Upgrading Your Car
You have a standard `Car` class (your `DetailView`). You want to add features.
In Django, this is most famously used for authentication.
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView
from .models import SecretDocument
# By adding 'LoginRequiredMixin', we've
# "mixed in" a feature.
#
# This view will now *automatically* check if a
# user is logged in. If they are not, it will
# redirect them to the login page.
#
# We get all this security with one line.
class SecretDocumentListView(LoginRequiredMixin, ListView):
model = SecretDocument
template_name = 'secrets/secret_list.html'
Signals are part of a "decoupling" pattern. They are a "broadcast system" that allows certain senders to notify a set of receivers that some action has just happened.
Analogy: A Radio Broadcast
A radio station (the sender) broadcasts a message, like "The weather is changing!"
This is powerful because the sender and receiver don't need to know about each other.
Django has many built-in signals. The most common are the model signals:
# my_app/models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
# We create a simple Profile model
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField(blank=True)
# This is the "receiver" function.
# It's "connected" to the User model's post_save signal.
@receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
# 'created' is True only the first time
if created:
# If a new User was just created,
# automatically create a Profile for them.
Profile.objects.create(user=instance)
print(f"Profile created for {instance.username}!")
# This makes the User model (the sender)
# completely unaware that the Profile model
# (the receiver) even exists. It's "decoupled".
Sample Output (in the console when a new User is created):
Profile created for new_user!
Middleware is a framework of hooks into Django's request/response processing. It's a series of "layers" that every request must pass through on its way to the view, and that every response must pass through on its way back to the user.
Analogy: Airport Security
This is the perfect analogy for middleware. The View is your gate.
Middleware is how Django handles its core security and session features. You can also write your own custom middleware, for example, to log all requests or to add a special header to all responses.
These are the two ways you can run Python-like logic inside your HTML templates.
A filter is used to transform the value of a variable.
Analogy: This is like a "filter" on your phone's camera. You have a variable (the photo), and you apply a filter to change how it looks.
The syntax is a pipe `|` character.
<p>{{ my_variable|lower }}</p>
<p>{{ my_list|length }}</p>
<p>{{ my_date|date:"Y-m-d" }}</p>
A tag is used to perform logic, like create a loop or an if-statement.
Analogy: This is like a "command" or "instruction" for the template. It doesn't just change a value; it does something.
The syntax is {% ... %}.
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}.</p>
{% else %}
<a href="/login/">Please log in.</a>
{% endif %}
<ul>
{% for product in product_list %}
<li>{{ product.name }}</li>
{% endfor %}
</ul>
Summary:
- Use a Filter {{ var|filter }} to change a variable's appearance.
- Use a Tag {% tag %} to do something (like logic or a loop).
3 questions · no sign-up, nothing stored
Progress is stored in this browser only - no sign-up, nothing sent anywhere.