Views and Templates β Rendering Article List |
\\n\\nViews and Templates β Rendering Article List
\\n\\nIn this chapter, you will learn how to use Django views to fetch data from the database and combine it with templates to render a list of article cards on the blog homepage.
\\n\\n\\n\\n
The Role of Views
\\n\\nViews are the core logic layer in Django, responsible for:
\\n\\n- \\n
- Receiving user requests (via the
requestparameter) \\n - Querying required data from the database \\n
- Passing data to templates for HTML rendering and returning the response to the user \\n
Django views come in two forms: Function-Based Views (FBV) and Class-Based Views (CBV).
\\n\\nIn the first eight chapters, we prioritize FBVβit is more intuitive and suitable for beginners to understand the request-handling flow.
\\n\\n\\n\\n
Basics of Function-Based Views
\\n\\nA Django view function receives a request parameter and returns an HttpResponse object.
Example
\\n\\n# File path: blog/views.py\\n\\nfrom django.shortcuts import render\\n\\nfrom .models import Post\\n\\ndef index(request):\\n\\n """Blog homepage: displays all articles"""\\n\\n # Query all articles from the database, ordered by creation time in descending order\\n posts = Post.objects.all().order_by('-created_at')\\n\\n # Three arguments for render():\\n # 1. request β the request object\\n # 2. template path β blog/index.html\\n # 3. context dictionary β data passed to the template\\n context = {\\n 'posts': posts,\\n 'title': 'TUTORIAL Blog - Home'\\n }\\n\\n return render(request, 'blog/index.html', context)\\n\\n\\nrender() is the most commonly used shortcut function in Django. It combines: loading the template β injecting data β generating HTML β returning the response.
\\n\\n
Django Template Syntax
\\n\\nDjango template syntax is very similar to Vue3 template syntax, but with some key differences:
\\n\\n| Usage | \\nDjango Template | \\nVue3 Template | \\n
|---|---|---|
| Output variable | \\n{{ variable }} | \\n {{ variable }} | \\n
| Loop | \\n{% for item in list %}...{% endfor %} | \\n v-for="item in list" | \\n
| Condition | \\n{% if cond %}...{% endif %} | \\n v-if="cond" | \\n
| URL generation | \\n{% url 'name' %} | \\n router-link to="name" | \\n
| Layout inheritance | \\n{% extends 'base.html' %} | \\n Component nesting | \\n
\\n\\n\\nKey difference: Django templates use
\\n{% %}for control tags, while Vue3 usesv-directives. Django templates are rendered on the server-sideβHTML is fully generated before sending to the browser. Vue3 is rendered on the client-sideβthe browser receives JavaScript and then constructs HTML.
\\n\\n
Template Inheritance: base.html
\\n\\nWhen multiple pages share the same navigation bar and footer, use template inheritance to avoid repetition.
\\n\\nThe parent template defines blocks, and child templates fill in specific content.
\\n\\nCreate the Parent Template: base.html
\\n\\nExample
\\n\\n\\n<!DOCTYPE html>\\n<html lang="zh-CN">\\n<head>\\n <meta charset="UTF-8">\\n <meta name="viewport" content="width=device-width, initial-scale=1.0">\\n <title>{% block title %}TUTORIAL Blog{% endblock %}</title>\\n <style>\\n * { margin: 0; padding: 0; box-sizing: border-box; }\\n body {\\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\\n background: #f5f5f5;\\n color: #333;\\n }\\n .navbar {\\n display: flex; justify-content: space-between; align-items: center;\\n padding: 16px 40px; background: #fff;\\n box-shadow: 0 2px 8px rgba(0,0,0,0.1);\\n }\\n .navbar .logo { font-size: 22px; font-weight: bold; color: #2c3e50; text-decoration: none; }\\n .navbar a { margin-left: 20px; text-decoration: none; color: #333; }\\n .container { max-width: 960px; margin: 40px auto; padding: 0 20px; }\\n .footer { text-align: center; padding: 20px; color: #999; border-top: 1px solid #eee; }\\n .section-title { font-size: 24px; margin-bottom: 20px; }\\n </style>\\n {% block extra_head %}{% endblock %}\\n</head>\\n<body>\\n <!-- Navigation Bar -->\\n <header class="navbar">\\n <a href="/" class="logo">TUTORIAL Blog</a>\\n <nav>\\n <a href="/">Home</a>\\n <a href="#">About</a>\\n </nav>\\n </header>\\n\\n <!-- Main Content Area (filled by child templates) -->\\n <main class="container">\\n {% block content %}\\n {% endblock %}\\n </main>\\n\\n <!-- Footer -->\\n <footer class="footer">\\n <p>Β© 2024 TUTORIAL Blog. Powered by Django.</p>\\n </footer>\\n</body>\\n</html>\\n\\n\\nCreate the Child Template: index.html
\\n\\nExample
\\n\\n\\n<!-- extends Must be at the very beginning -->\\n{% extends 'blog/base.html' %}\\n\\n{% block title %}{{ title }}{% endblock %}\\n\\n{% block content %}\\n <h2 class="section-title">Latest Posts</h2>\\n {% if posts %}\\n <div class="article-grid">\\n {% for post in posts %}\\n <div class="article-card">\\n <div class="card-content">\\n <span class="card-category">{{ post.category.name }}</span>\\n <h3>{{ post.title }}</h3>\\n <p>{{ post.summary|truncatechars:80 }}</p>\\n <span class="card-date">{{ post.created_at|date:"Y-m-d" }}</span>\\n </div>\\n </div>\\n {% endfor %}\\n </div>\\n {% else %}\\n <p class="empty-tip">No posts yet, stay tuned.</p>\\n {% endif %}\\n{% endblock %}\\n\\n\\nKey points used in the template:
\\n\\n| Syntax | \\nMeaning | \\n
|---|---|
{% extends 'blog/base.html' %} | \\n Inherits the parent template; must be placed on the first line | \\n
{% block content %}...{% endblock %} | \\n Fills the content block defined in the parent template | \\n
{{ post.category.name }} | \\n Accesses attributes of a related object via a foreign key | \\n
{{ post.summary|truncatechars:80 }} | \\n Filter: truncates to the first 80 characters | \\n
{{ post.created_at|date:"Y-m-d" }} | \\n Filter: formats the date | \\n
\\n\\n\\nIn Django templates, filters are denoted by the pipe symbol
\\n|, placed after a variable to format its output. Common filters:date,truncatechars,length,default.
\\n\\n
Add Article List Styling
\\n\\nAppend the following CSS to the <style> block in base.html:
Example
\\n\\n/* Article Card Grid Layout */\\n.article-grid {\\n display: grid;\\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\\n gap: 24px;\\n}\\n\\n.article-card {\\n background: #fff;\\n border-radius: 12px;\\n overflow: hidden;\\n box-shadow: 0 2px 12px rgba(0,0,0,0.08);\\n transition: transform 0.2s, box-shadow 0.2s;\\n}\\n\\n.article-card:hover {\\n transform: translateY(-4px);\\n box-shadow: 0 8px 24px rgba(0,0,0,0.12);\\n}\\n\\n.card-content {\\n padding: 20px;\\n}\\n\\n.card-category {\\n display: inline-block;\\n padding: 2px 10px;\\n background: #e8f5e9;\\n color: #2e7d32;\\n border-radius: 12px;\\n font-size: 12px;\\n margin-bottom: 8px;\\n}\\n\\n.article-card h3 {\\n font-size: 18px;\\n margin-bottom: 8px;\\n color: #222;\\n}\\n\\n.article-card p {\\n font-size: 14px;\\n color: #666;\\n line-height: 1.6;\\n margin-bottom: 12px;\\n}\\n\\n.card-date {\\n font-size: 12px;\\n color: #999;\\n}\\n\\n.empty-tip {\\n text-align: center;\\n color: #999;\\n padding: 60px 0;\\n font-size: 16px;\\n}\\n\\n\\n\\n\\n
Hands-on: Verify Homepage Effect
\\n\\nEnsure the following are properly set up:
\\n\\n- \\n
models.pydefines thePostandCategorymodels, and migrations have been applied \\n - At least 3β5 articles have been added via the Admin backend (assigned to different categories) \\n
- The
indexfunction inviews.pyqueries articles from the database and passes them to the template \\n - The route
/inurls.pypoints to theindexview \\n
Start the server and visit the homepageβyou should see a list of dynamically rendered article cards populated from the database.
\\n\\n\\n\\n
Chapter Summary
\\n\\nIn this chapter, you mastered the core collaboration between Django views and templates: views.py queries data from the database and passes it into the context, render() renders the template, base.html defines the layout with blocks, child templates use extends to inherit and fill content, and Django template syntax ({{ }}, {% %}, filters).
Now the blog homepage is database-driven and no longer hardcoded.
YouTip