Flask 使用 Jinja2 模板引擎来渲染动态 HTML 页面,并提供了静态文件服务功能。
Jinja2 模板引擎
- 变量替换:
{{ variable }}
- 控制结构:
{% for %}, {% if %}
- 模板继承:
{% extends %}, {% block %}
- 过滤器:
{{ variable|filter }}
基本模板使用
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def index():
# 传递变量到模板
return render_template('index.html', title='Home Page', username='John Doe')
@app.route('/users')
def users():
user_list = [{'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}, {'name': 'Charlie', 'age': 35}]
return render_template('users.html', users=user_list)
@app.route('/post/<int:post_id>')
def show_post(post_id):
post = {'id': post_id, 'title': f'Post {post_id}', 'content': 'This is the post content.'}
return render_template('post.html', post=post)
基础模板
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}My Flask App{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
<body>
<nav>
<ul>
<li><a href="{{ url_for('index') }}">Home</a></li>
<li><a href="{{ url_for('users') }}">Users</a></li>
</ul>
</nav>
<div class="content">
{% block content %}
<!-- 子模板内容将在这里插入 -->
{% endblock %}
</div>
<footer>
<p>© 2024 My Flask App</p>
</footer>
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
</body>
</html>
继承模板
{% extends "base.html" %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h1>Welcome, {{ username }}!</h1>
<p>This is the home page of our Flask application.</p>
<div class="user-info">
<h2>User Information</h2>
<p><strong>Name:</strong> {{ username }}</p>
<p><strong>Login Time:</strong> {{ current_time }}</p>
</div>
{% if messages %}
<div class="messages">
<h3>Messages:</h3>
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% endblock %}
Jinja2 控制结构
<!-- if 语句 -->
{% if user %}
<p>Welcome, {{ user.name }}!</p>
{% elif guest %}
<p>Welcome, Guest!</p>
{% else %}
<p>Please log in.</p>
{% endif %}
<!-- for 循环 -->
<ul>
{% for item in items %}
<li>{{ loop.index }}. {{ item.name }}</li>
{% else %}
<li>No items found.</li>
{% endfor %}
</ul>
<!-- 循环变量 -->
<table>
{% for user in users %}
<tr class="{{ loop.cycle('odd', 'even') }}">
<td>{{ loop.index }}</td>
<td>{{ user.name }}</td>
<td>{{ user.email }}</td>
</tr>
{% endfor %}
</table>
Jinja2 过滤器
<!-- 字符串过滤器 -->
<p>{{ title|upper }}</p>
<p>{{ description|lower|truncate(50) }}</p>
<p>{{ content|striptags }}</p>
<p>{{ name|default("Anonymous") }}</p>
<!-- 数字过滤器 -->
<p>Price: {{ price|round(2) }}</p>
<p>Items: {{ items|length }}</p>
<p>Percentage: {{ value|float * 100 }}%</p>
<!-- 日期过滤器 -->
<p>Today: {{ current_time|datetimeformat('%Y-%m-%d') }}</p>
<p>Relative: {{ post_date|timesince }}</p>
<!-- 列表过滤器 -->
<p>First: {{ list|first }}</p>
<p>Last: {{ list|last }}</p>
<p>Joined: {{ tags|join(", ") }}</p>
<!-- 自定义过滤器 -->
<p>{{ text|markdown }}</p>
<p>{{ url|urlencode }}</p>
静态文件处理
/* static/css/style.css */
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
nav {
background-color: #333;
color: white;
padding: 1rem;
}
nav ul {
list-style: none;
padding: 0;
margin: 0;
display: flex;
}
nav li {
margin-right: 1rem;
}
nav a {
color: white;
text-decoration: none;
}
.content {
padding: 2rem;
max-width: 1200px;
margin: 0 auto;
}
.user-info {
background: white;
padding: 1rem;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
// static/js/app.js
document.addEventListener('DOMContentLoaded', function() {
console.log('Flask app loaded successfully');
// 示例:添加交互功能
const buttons = document.querySelectorAll('.btn-action');
buttons.forEach(button => {
button.addEventListener('click', function() {
alert('Button clicked: ' + this.textContent);
});
});
// AJAX 请求示例
function loadUserData(userId) {
fetch(`/api/users/${userId}`)
.then(response => response.json())
.then(data => {
console.log('User data:', data);
});
}
});
自定义过滤器
from flask import Flask
import datetime
app = Flask(__name__)
# 自定义过滤器
@app.template_filter('datetimeformat')
def datetimeformat(value, format='%Y-%m-%d %H:%M:%S'):
if isinstance(value, datetime.datetime):
return value.strftime(format)
return value
@app.template_filter('timesince')
def timesince(value):
if isinstance(value, datetime.datetime):
now = datetime.datetime.now()
diff = now - value
if diff.days > 365:
return f"{diff.days // 365} years ago"
elif diff.days > 30:
return f"{diff.days // 30} months ago"
elif diff.days > 0:
return f"{diff.days} days ago"
elif diff.seconds > 3600:
return f"{diff.seconds // 3600} hours ago"
elif diff.seconds > 60:
return f"{diff.seconds // 60} minutes ago"
else:
return "just now"
return value
@app.template_filter('markdown')
def markdown_filter(text):
# 需要安装 markdown 库: pip install markdown
import markdown
return markdown.markdown(text)
# 在模板中使用自定义过滤器
# {{ post.date|datetimeformat('%Y-%m-%d') }}
# {{ post.date|timesince }}
# {{ content|markdown }}
提示: 这是一个重要的概念,需要特别注意理解和掌握。
注意: 这是一个常见的错误点,请避免犯同样的错误。
评论
请 登录 后发表评论