Templates, Static Files and Layouts
Template inheritance
{# templates/base.html #}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{% block title %}My App{% endblock %}</title>
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}">
</head>
<body>
{% include "partials/header.html" %}
<main>
{% with messages = get_flashed_messages(with_categories=true) %}
{% for category, message in messages %}
<div class="alert alert-{{ category }}">{{ message }}</div>
{% endfor %}
{% endwith %}
{% block content %}{% endblock %}
</main>
</body>
</html>
{# templates/projects/list.html #}
{% extends "base.html" %}
{% block title %}Projects{% endblock %}
{% block content %}
<h1>Projects</h1>
{% for p in projects %}
<a href="{{ url_for('projects.detail', slug=p.slug) }}">{{ p.title }}</a>
{% else %}
<p>No projects yet.</p>
{% endfor %}
{% endblock %}
url_for, always
url_for('projects.detail', slug=p.slug) builds URLs from endpoint names, so changing a route path never breaks links. A missing endpoint raises an error immediately, which is easy to catch in tests.
Escaping and safety
Jinja2 escapes variables automatically: a project title containing <script> is shown as text. Never use |safe on user-provided content. If you render user Markdown, use a renderer that escapes HTML first, then mark the result safe.
Macros: reusable components
{# templates/macros.html #}
{% macro card(title, body, href) %}
<a class="card" href="{{ href }}"><h3>{{ title }}</h3><p>{{ body }}</p></a>
{% endmacro %}
{% from "macros.html" import card %}
{{ card(p.title, p.summary, url_for('projects.detail', slug=p.slug)) }}
Context processors
Make values available in every template:
@app.context_processor
def inject_globals():
return {"site_name": "PandaDev", "year": datetime.utcnow().year}
Flash messages
from flask import flash, redirect, url_for
flash("Project saved.", "success")
return redirect(url_for("projects.list"))
Use the Post/Redirect/Get pattern: after a successful POST, redirect, so refreshing the page does not resubmit the form.
Exercise
Build a base layout with header, flash messages and footer; a projects list page and a detail page using a card macro; and a 404 template registered with @app.errorhandler(404).
Check yourself
- Why build links with
url_for? - When is
|safeacceptable? - What problem does Post/Redirect/Get solve?
Ваш прогресс сохраняется только в этом браузере.
Отправить на проверку (10 баллов)