教师演示 45 分钟 + 学生练习 45 分钟 · 前置条件:Linux 服务器 + Python 3 + 安全组已放行 5000 端口
Flask 核心只做两件事:
# 创建工作目录并进入 mkdir -p ~/flask_learn && cd ~/flask_learn # 创建 Python 虚拟环境(把项目依赖和系统隔离,互不干扰) python3 -m venv venv # 激活虚拟环境(成功后命令行前面出现 (venv) 标志) source venv/bin/activate # 安装 Flask pip install flask
nano app.py
from flask import Flask # 从 flask 包导入 Flask 类 app = Flask(__name__) # 创建应用实例 # @app.route('/') 叫做"路由装饰器" # 作用:当用户访问网站首页(/)时,执行下面的函数 @app.route('/') def index(): return '<h1>🎉 Hello Flask!</h1><p>我的第一个 Flask 应用成功运行!</p>' # 启动应用 # host='0.0.0.0' → 允许外网访问 # port=5000 → 监听 5000 端口 # debug=True → 调试模式,改代码后自动重启 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
python app.py
浏览器访问 http://你的服务器IP:5000
@app.route('/') 把网址 / 和函数 index() 绑定在一起。Ctrl+C 停止程序,编辑 app.py,替换全部内容:
from flask import Flask app = Flask(__name__) # ---- 路由1:首页 ---- @app.route('/') def index(): return ''' <h1>🏠 Flask 路由演示</h1> <ul> <li><a href="/about">📖 关于本站</a></li> <li><a href="/user/张三">👤 用户:张三</a></li> <li><a href="/user/李四">👤 用户:李四</a></li> <li><a href="/score/95">📊 查分:95</a></li> <li><a href="/score/48">📊 查分:48</a></li> <li><a href="/calc/10/20">🧮 计算 10+20</a></li> </ul> ''' # ---- 路由2:固定路由 ---- @app.route('/about') def about(): return '<h1>📖 关于本站</h1><p>保山学院 Flask 学习项目。</p><a href="/">← 返回</a>' # ---- 路由3:带变量的路由 ---- # <name> 是路由变量:访问 /user/张三 时,name 就等于 "张三" @app.route('/user/<name>') def user(name): return f'<h1>👤 你好,{name}!</h1><a href="/">← 返回</a>' # ---- 路由4:限定变量类型为整数 ---- # <int:score> 表示 score 必须是整数 @app.route('/score/<int:score>') def show_score(score): if score >= 90: level = '🌟 优秀' elif score >= 60: level = '✅ 及格' else: level = '❌ 不及格' return f'<h1>📊 {score} 分 → {level}</h1><a href="/">← 返回</a>' # ---- 路由5:多个变量 ---- @app.route('/calc/<int:a>/<int:b>') def calc(a, b): return f'<h1>🧮 {a} + {b} = {a + b}</h1><a href="/">← 返回</a>' if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
python app.py
浏览器访问首页,点击每个链接看效果:
| 访问地址 | 页面效果 | 涉及知识点 |
|---|---|---|
/ | 首页,显示 6 个链接 | 固定路由 |
/about | 关于本站 | 固定路由 |
/user/张三 | 显示"你好,张三" | 动态路由变量 <name> |
/score/95 | 95 分 → 🌟 优秀 | 类型限定 <int:score> |
/score/48 | 48 分 → ❌ 不及格 | if/elif/else 条件判断 |
/calc/10/20 | 10 + 20 = 30 | 多个变量 |
@app.route('/about') → 网址固定不变@app.route('/user/<name>') → URL 中的值自动传给函数参数<int:score> → 只接受整数,非整数返回 404
Ctrl+C 停止程序。
# 创建模板目录和静态文件目录
mkdir -p templates static
nano static/style.css
/* 全局样式 */ body { font-family: "Microsoft YaHei", "PingFang SC", sans-serif; max-width: 750px; margin: 0 auto; padding: 20px; background: #f0f4f8; color: #333; line-height: 1.8; } /* 导航栏 */ nav { background: #2c3e50; padding: 12px 20px; border-radius: 8px; margin-bottom: 25px; } nav a { color: #fff; text-decoration: none; margin-right: 20px; } nav a:hover { color: #3498db; } /* 标题 */ h1 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 8px; } /* 卡片 */ .card { background: #fff; border-radius: 10px; padding: 20px 25px; margin: 15px 0; box-shadow: 0 2px 8px rgba(0,0,0,0.08); } /* 表格 */ table { width: 100%; border-collapse: collapse; } th, td { padding: 10px 14px; text-align: left; border-bottom: 1px solid #eee; } th { background: #2c3e50; color: #fff; } tr:hover { background: #f1f8ff; } /* 页脚 */ footer { text-align: center; color: #aaa; margin-top: 30px; padding-top: 15px; border-top: 1px solid #ddd; }
nano templates/base.html
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>{% block title %}Flask学习{% endblock %}</title> <!-- url_for 自动生成静态文件的正确路径 --> <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}"> </head> <body> <!-- 导航栏:所有页面共享 --> <nav> <a href="/">🏠 首页</a> <a href="/user/同学">👤 用户页</a> <a href="/students">📋 学生列表</a> </nav> <!-- 子模板在这里填内容 --> {% block content %}{% endblock %} <footer>保山学院 · Flask 框架学习</footer> </body> </html>
base.html 是"骨架"(导航栏 + 页脚),子模板用 {% extends "base.html" %} 继承它,只写不同的内容。好处:改一处,所有页面一起变。
nano templates/index.html
<!-- 继承基础模板,自动获得导航栏和页脚 --> {% extends "base.html" %} {% block title %}首页{% endblock %} {% block content %} <h1>🎉 Flask 模板演示</h1> <div class="card"> <h2>📚 什么是模板?</h2> <p>模板 = 带空格的 HTML。Python 传数据,Jinja2 填进去。</p> <p>当前时间:<strong>{{ now }}</strong></p> </div> <div class="card"> <h2>🧪 Jinja2 核心语法</h2> <p><code>{{ "{{ 变量 }}" }}</code> → 输出变量的值</p> <p><code>{{ "{% if 条件 %}" }}</code> → 条件判断</p> <p><code>{{ "{% for x in 列表 %}" }}</code> → 循环</p> <p><code>{{ "{{ 变量 | 过滤器 }}" }}</code> → 处理后再输出</p> </div> {% endblock %}
更新 app.py 主程序:
from flask import Flask, render_template from datetime import datetime app = Flask(__name__) @app.route('/') def index(): return render_template('index.html', now=datetime.now().strftime('%Y-%m-%d %H:%M:%S')) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
python app.py
不需要停止程序(debug 模式下新增模板后刷新浏览器即可)。
nano templates/user.html
{% extends "base.html" %}
{% block title %}用户:{{ name }}{% endblock %}
{% block content %}
<h1>👤 用户页面</h1>
<div class="card">
<h2>模板变量 & 过滤器</h2>
<p>原始值:<strong>{{ name }}</strong></p>
<!-- | upper 过滤器:转为大写 -->
<p>转大写:<strong>{{ name | upper }}</strong></p>
<!-- | length 过滤器:计算长度 -->
<p>字符数:<strong>{{ name | length }}</strong></p>
</div>
<div class="card">
<h2>条件判断(if / elif / else)</h2>
{% if name == "管理员" %}
<p style="color:red;">⚠️ 欢迎管理员,您拥有最高权限!</p>
{% elif name | length > 4 %}
<p>你的名字挺长的(超过4个字符)!</p>
{% else %}
<p>{{ name }},欢迎你来学 Flask!</p>
{% endif %}
</div>
{% endblock %}
在 app.py 的 if __name__ 之前追加一个路由:
@app.route('/user/<name>') def user_page(name): return render_template('user.html', name=name)
/user/张三 → 看到变量和过滤器效果/user/管理员 → if 条件判断生效,红色管理员提示
nano templates/students.html
{% extends "base.html" %}
{% block title %}学生列表{% endblock %}
{% block content %}
<h1>📋 学生信息列表</h1>
<div class="card">
<p>共 <strong>{{ students | length }}</strong> 名学生</p>
<table>
<tr>
<th>序号</th>
<th>姓名</th>
<th>专业</th>
<th>成绩</th>
<th>评定</th>
</tr>
<!-- for 循环遍历列表,loop.index 是从 1 开始的序号 -->
{% for s in students %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ s.name }}</td>
<td>{{ s.major }}</td>
<td>{{ s.score }}</td>
<td>
{% if s.score >= 90 %}🌟 优秀
{% elif s.score >= 60 %}✅ 及格
{% else %}❌ 不及格
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
在 app.py 的 if __name__ 之前再追加:
@app.route('/students') def student_list(): students = [ {'name': '张三', 'major': '计算机科学', 'score': 92}, {'name': '李四', 'major': '大数据技术', 'score': 78}, {'name': '王五', 'major': '人工智能', 'score': 55}, {'name': '赵六', 'major': '软件工程', 'score': 88}, {'name': '孙七', 'major': '大数据技术', 'score': 95}, ] return render_template('students.html', students=students)
/students → 带样式的表格,成绩旁自动显示🌟/✅/❌。@app.route() 把网址绑定到函数render_template() 渲染 HTML,Python 只管传数据{{ 变量 }}、{% if %}、{% for %}、| 过滤器
按顺序操作,每完成一步就刷新浏览器看效果
# 登录服务器 ssh root@你的IP # 创建目录、虚拟环境、安装 Flask mkdir -p ~/myflask && cd ~/myflask python3 -m venv venv source venv/bin/activate pip install flask
nano app.py
from flask import Flask app = Flask(__name__) @app.route('/') def index(): return ''' <h1>🎉 你好,我是张三!</h1> <p>这是我的第一个 Flask 应用。</p> <hr> <h3>我的页面:</h3> <ul> <li><a href="/about">📖 关于我</a></li> <li><a href="/greet/老师">👋 问候老师</a></li> <li><a href="/greet/同桌">👋 问候同桌</a></li> <li><a href="/score/95">📊 查分 95</a></li> <li><a href="/score/42">📊 查分 42</a></li> <li><a href="/calc/12/30">🧮 计算 12+30</a></li> <li><a href="/weather/保山">🌤️ 保山天气</a></li> <li><a href="/weather/昆明">🌤️ 昆明天气</a></li> </ul> ''' @app.route('/about') def about(): return '<h1>📖 关于我</h1><p>我叫张三,大数据技术专业,喜欢编程和篮球。</p><a href="/">← 返回</a>' @app.route('/greet/<name>') def greet(name): return f'<h1>👋 {name},你好!</h1><p>很高兴认识你!</p><a href="/">← 返回</a>' @app.route('/score/<int:score>') def show_score(score): if score >= 90: result = '🌟 优秀' elif score >= 60: result = '✅ 及格' else: result = '❌ 不及格' return f'<h1>📊 {score} 分 → {result}</h1><a href="/">← 返回</a>' @app.route('/calc/<int:a>/<int:b>') def calc(a, b): return f'<h1>🧮 {a} + {b} = {a + b}</h1><a href="/">← 返回</a>' @app.route('/weather/<city>') def weather(city): if city == '保山': info = '☀️ 晴天 22℃' elif city == '昆明': info = '⛅ 多云 18℃' elif city == '北京': info = '🌬️ 大风 12℃' else: info = '🌍 暂无该城市天气数据' return f'<h1>🌤️ {city} 天气</h1><p>{info}</p><a href="/">← 返回</a>' if __name__ == '__main__': app.run(host='0.0.0.0', port=5000, debug=True)
python app.py
浏览器访问 http://你的IP:5000,点击每个链接看效果。
Ctrl+C 停止程序。
cd ~/myflask mkdir -p templates static
nano static/style.css
body {
font-family: "Microsoft YaHei", "PingFang SC", sans-serif;
max-width: 700px; margin: 0 auto; padding: 20px;
background: #f0f4f8; color: #333; line-height: 1.8;
}
nav { background: #2c3e50; padding: 12px 20px; border-radius: 8px; margin-bottom: 20px; }
nav a { color: #fff; text-decoration: none; margin-right: 18px; }
nav a:hover { color: #3498db; }
h1 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 8px; }
.card { background: #fff; border-radius: 10px; padding: 20px; margin: 12px 0;
box-shadow: 0 2px 6px rgba(0,0,0,0.08); }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 10px; text-align: left; border-bottom: 1px solid #eee; }
th { background: #2c3e50; color: #fff; }
tr:hover { background: #f1f8ff; }
footer { text-align: center; color: #aaa; margin-top: 30px; }
nano templates/base.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>{% block title %}Flask练习{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav>
<a href="/">🏠 首页</a>
<a href="/about">📖 关于我</a>
<a href="/classmates">📋 同学列表</a>
</nav>
{% block content %}{% endblock %}
<footer>保山学院 · 我的 Flask 练习</footer>
</body>
</html>
nano templates/index.html
{% extends "base.html" %}
{% block title %}首页{% endblock %}
{% block content %}
<h1>🎉 我的 Flask 练习</h1>
<div class="card">
<p>👤 姓名:<strong>{{ my_name }}</strong></p>
<p>🎓 专业:<strong>{{ my_major }}</strong></p>
<p>🕐 当前时间:<strong>{{ now }}</strong></p>
</div>
<div class="card">
<h2>🔗 快速导航</h2>
<p><a href="/about">📖 关于我</a> · <a href="/classmates">📋 同学列表</a></p>
</div>
{% endblock %}
nano app.py
from flask import Flask, render_template
from datetime import datetime
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html',
my_name='张三', # ← 改成你的名字
my_major='大数据技术', # ← 改成你的专业
now=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
@app.route('/about')
def about():
return render_template('about.html',
my_name='张三', # ← 改成你的名字
hobbies=['编程', '篮球', '听音乐', '打游戏']) # ← 改成你的爱好
@app.route('/greet/<name>')
def greet(name):
return f'<h1>👋 {name},你好!</h1><a href="/">← 返回</a>'
@app.route('/classmates')
def classmates():
data = [
{'name': '张三', 'hobby': '编程', 'score': 92},
{'name': '李四', 'hobby': '篮球', 'score': 78},
{'name': '王五', 'hobby': '画画', 'score': 55},
{'name': '赵六', 'hobby': '编程', 'score': 88},
{'name': '孙七', 'hobby': '跑步', 'score': 95},
]
return render_template('classmates.html', classmates=data)
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
python app.py
浏览器访问 http://你的IP:5000,看到带导航栏和卡片样式的首页。此时"关于我"和"同学列表"还不能用——下面马上创建。
nano templates/about.html
{% extends "base.html" %}
{% block title %}关于我{% endblock %}
{% block content %}
<h1>📖 关于我</h1>
<div class="card">
<p>大家好,我叫 <strong>{{ my_name }}</strong>。</p>
<h3>我的爱好:</h3>
<ul>
{% for hobby in hobbies %}
<li>{{ hobby }}</li>
{% endfor %}
</ul>
<p>共 <strong>{{ hobbies | length }}</strong> 个爱好。</p>
</div>
{% endblock %}
浏览器访问 http://你的IP:5000/about,看到你的爱好列表。
nano templates/classmates.html
{% extends "base.html" %}
{% block title %}同学列表{% endblock %}
{% block content %}
<h1>📋 我的同学们</h1>
<div class="card">
<p>共 <strong>{{ classmates | length }}</strong> 位同学</p>
<table>
<tr>
<th>序号</th><th>姓名</th><th>爱好</th>
<th>成绩</th><th>评定</th>
</tr>
{% for c in classmates %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ c.name }}</td>
<td>{{ c.hobby }}</td>
<td>{{ c.score }}</td>
<td>
{% if c.score >= 90 %}🌟 优秀
{% elif c.score >= 60 %}✅ 及格
{% else %}❌ 不及格
{% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
浏览器访问 http://你的IP:5000/classmates,看到完整的同学列表表格。导航栏三个链接全部可用。
| 概念 | 说明 | 类比 |
|---|---|---|
@app.route('/') | 路由:网址 → 函数 | 门牌号 → 房间 |
<name> | 动态路由变量 | 快递单上的收件人 |
<int:score> | 限制变量为整数 | 只收数字的输入框 |
render_template() | 渲染模板 | 把答案填进试卷 |
{{ 变量 }} | 输出变量值 | 填空题的横线 |
{% if %} | 条件判断 | 如果…就… |
{% for %} | 循环 | 逐个点名 |
{% extends %} | 模板继承 | 共用同一栋楼 |
{{ x | upper }} | 过滤器 | 加工处理 |
url_for() | 自动生成 URL | 自动导航 |
| 问题 | 解决方法 |
|---|---|
| 浏览器访问不了 | 检查安全组是否放行 5000 端口;确认代码里写了 host='0.0.0.0' |
| 改了代码没生效 | 确认 debug=True;或 Ctrl+C 后重新运行 python app.py |
TemplateNotFound | 检查文件是否在 templates/ 文件夹里,文件名拼写是否一致 |
| 样式没生效 | CSS 是否在 static/ 文件夹里;浏览器 Ctrl+Shift+R 强制刷新 |