Python Tutorial
Django Views
A view is a Python function that takes a request and returns a response. Start with a simple HttpResponse, then move to templates later.
Your First View
Open members/views.py and replace it with:
from django.http import HttpResponse
def members(request):
return HttpResponse("Hello world!")request is an HttpRequest object (method, path, user, POST data). The view must return an HttpResponse (or a subclass such as a redirect).
Function-Based vs Class-Based
This tutorial uses function-based views — one function per page. Django also has class-based views (ListView, DetailView) for reusable patterns. Learn functions first; classes wrap the same ideas.
What a View Can Return
- Plain text or HTML via
HttpResponse - A rendered template via
render()(next chapters) - JSON via
JsonResponse - A redirect via
redirect("url-name")
The View Is Not Live Yet
Django does not call a view until a URL pattern points at it. The next chapter wires /members/ to this function.
📘 Real-World Deep Dive
Django views are the connectors: they read from the URL router, hit the ORM, hand the data to a template, and return a response. Three function forms (<code>function-based</code>, <code>class-based</code>, and DRF's <code>APIView</code>) cover 95% of real apps.
Real-Life Scenario
A class-based view for the blog detail page with caching, pagination, and a clean error path when the slug is invalid.
Real-Life Example
from django.views.generic import DetailView
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
from .models import Post
@method_decorator(cache_page(60 * 5), name="dispatch")
class PostDetail(DetailView):
"""Cached detail view; raises Http404 for missing or unpublished slugs."""
model = Post
template_name = "blog/detail.html"
context_object_name = "post"
slug_field = "slug"
slug_url_kwarg = "slug"
def get_queryset(self):
return Post.objects.select_related("author").filter(pub__lte=__import__("django").utils.timezone.now())
# urls.py
# from django.urls import path
# from .views import PostDetail
# urlpatterns = [path("<slug:slug>/", PostDetail.as_view(), name="detail")]
# template syntax at the bottom:
# <article>
# <h1>{{ post.title }}</h1>
# <p>{{ post.pub|date:"F j, Y" }} — by {{ post.author.get_full_name }}</p>
# <div>{{ post.body|linebreaks }}</div>
# </article>Expected Output
(served via cached DetailView; pagination query parameters wired with Paginator)Common mistakes
- Don't pass
request.sessionqueries through CBVs — converters buy you nothing. - Returning the queryset with
select_relatedmakes a big difference when one query loads many posts. - Decorator order matters:
@method_decorator(login_required)must wrap before@cache_page
🚀 Performance & Best Practices
- Cache full pages with
@cache_page; cache fragments with the{% cache %}template tag. - For millions of rows, switch from CBVs to async-compatible
async defviews in 4.x+. - Combine
etagwithLast-Modifiedfor cheap cache validation.
🧪 Try It Yourself
- Build a
JSONResponseMixinthat returns the same data as JSON. - Add a per-author
AuthorPostsViewreusing the same cache decorator. - Replace the python
__import__("django")...pattern with a regular import in your project.