初识Flask - Python轻量级Web框架入门指南
你有没有过这种想法?
——想用Python搭个极简的留言板,让朋友留两句话;
——写个API,把自己爬虫爬的小数据暴露出来给小程序/网页用;
——甚至弄个个人小站,放放自己的练手项目?
如果有,那Flask,这个被誉为「Python微框架天花板入门款」的东西,绝对是你首选的武器!
1. Flask简介
1.1 什么是Flask?
Flask是由Armin Ronacher在2010年创建的Python微框架,它基于成熟的Werkzeug WSGI工具箱和Jinja2模板引擎,现在已成为最受欢迎的Python Web框架之一。
它的「微」不是指功能少,而是核心极致简洁——只保留了Web开发最基础的部分(路由、模板、响应),其他功能(数据库、表单验证、用户认证等)全靠扩展按需添加,完全不强制你用特定的工具或库。
1.2 Flask的核心特点
- 轻量易上手:核心代码只有几千行,半天就能跑通第一个完整应用
- 极高灵活性:想怎么搭项目结构、用什么数据库都随你
- 丰富的扩展生态:官方/第三方扩展覆盖了几乎所有Web开发场景
- 社区活跃文档全:遇到问题搜一搜就能找到解决方案
1.3 与同级别Python框架对比
2. Flask安装与环境准备
2.1 环境要求
- Python 3.7 或更高版本
- pip包管理器
- 虚拟环境(强烈推荐,避免污染系统Python环境)
2.2 创建虚拟环境
首先新建一个项目文件夹,比如叫flask-demo,然后在里面打开终端执行:
# 环境搭建-创建/激活虚拟环境
# 1. 创建虚拟环境(flask_env是环境名,可自定义)
python -m venv flask_env
# 2. 激活虚拟环境
# macOS/Linux
source flask_env/bin/activate
# Windows (CMD/旧PowerShell)
flask_env\Scripts\activate
如果是**新版PowerShell (Win11/Win10 20H2+)**,需要先允许本地脚本执行:
```powershell
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
```
然后用`.\flask_env\Scripts\Activate.ps1`激活。
激活成功后,终端开头会出现(flask_env)的标识,接下来所有操作都在这个隔离的环境里进行。
# 3. 升级pip(可选但推荐)
pip install --upgrade pip
2.3 安装Flask
# 安装最新稳定版Flask
pip install Flask
# 验证安装(如果输出版本号说明成功)
python -c "import flask; print(flask.__version__)"
3. 第一个Flask应用:Hello World!
敲黑板!这里的代码虽然短,但包含了Flask应用的全部核心元素!
3.1 创建应用文件
在flask-demo目录下新建app.py:
# app.py
from flask import Flask
# 1. 创建Flask应用实例
# __name__是Flask的「导航员」——告诉它从当前文件所在目录找templates/static等资源
app = Flask(__name__)
# 2. 定义路由装饰器+处理函数
# @app.route('/')把「根路径http://127.0.0.1:5000/」映射到下面的hello_world函数
@app.route('/')
def hello_world():
# 处理函数的返回值就是给浏览器的响应内容
return '<h1>🎉 恭喜你,第一个Flask应用跑通了!</h1>'
# 3. 启动应用(仅在直接运行app.py时生效)
if __name__ == '__main__':
# debug=True开启调试模式:代码修改后自动重启、显示详细错误信息
app.run(debug=True)
3.2 运行并访问应用
在激活虚拟环境的终端里执行:
终端会显示类似这样的信息:
* Running on http://127.0.0.1:5000/
* Restarting with stat
* Debugger is active!
* Debugger PIN: xxx-xxx-xxx
打开浏览器访问http://127.0.0.1:5000/,就能看到你的Hello World页面啦!
`app.run(debug=True)`开启的调试模式**非常危险**——它会暴露代码、配置,甚至允许用户在服务器上执行Python代码!
入门练手用没关系,但正式上线一定要关掉,换成专业的WSGI服务器(比如Gunicorn)。
4. Flask核心概念一:路由系统
路由就是把URL路径和处理函数绑定起来的规则,是Flask应用的「入口管理器」。
4.1 基本路由
# 根路径
@app.route('/')
def index():
return '首页'
# 带固定字符串的路径
@app.route('/about')
def about():
return '关于我们'
4.2 带变量的路由(URL转换器)
你可以用<变量名>的方式在URL里加动态内容,还可以用<转换器:变量名>限制变量类型:
# 字符串变量(默认)
@app.route('/user/<username>')
def user_profile(username):
return f'你好,{username}!'
# 整数变量
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'这是第 {post_id} 篇文章'
# 路径变量(含斜杠)
@app.route('/files/<path:file_path>')
def show_file(file_path):
# 模拟显示文件路径,实际应用要注意安全!
return f'你请求的文件路径是:{file_path}'
4.3 限制HTTP方法
默认情况下,Flask路由只接受GET请求,如果需要接受POST、PUT等方法,要在@app.route里加methods参数:
from flask import request # 别忘了导入request对象!
# 同时接受GET和POST请求
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
# 处理POST请求:比如获取表单数据
return '正在处理登录请求...'
else:
# 处理GET请求:比如显示登录表单
return '<form method="post"><input type="text" name="username"><button type="submit">登录</button></form>'
# 处理GET查询参数(比如/search?q=Flask)
@app.route('/search')
def search():
# request.args.get('参数名', '默认值')获取URL中的查询参数
keyword = request.args.get('q', '暂无关键词')
return f'搜索关键词:{keyword}'
5. Flask核心概念二:Jinja2模板引擎
直接在Python代码里写HTML太丑了!Flask内置了Jinja2模板引擎,让你把HTML(视图)和Python(逻辑)分开写。
5.1 基本模板使用
- 首先在
flask-demo目录下新建templates文件夹(名字必须是templates,不能改!)
- 在
templates里新建hello.html:
<!-- templates/hello.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Jinja2变量:用{{ 变量名 }}包裹 -->
<title>{{ page_title }}</title>
</head>
<body>
<h1>你好,{{ user_name }}!👋</h1>
<!-- Jinja2条件判断:用{% if ... %} {% elif ... %} {% else %} {% endif %}包裹 -->
{% if user_age >= 18 %}
<p>你已经成年啦!</p>
{% else %}
<p>你还未成年哦~</p>
{% endif %}
<!-- Jinja2循环:用{% for ... in ... %} {% endfor %}包裹 -->
<h3>最近读过的书:</h3>
<ul>
{% for book in books %}
<li>{{ book.title }} - {{ book.author }}</li>
{% endfor %}
</ul>
</body>
</html>
- 在
app.py里用render_template渲染模板:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/hello/<name>/<int:age>')
def hello_template(name, age):
# 准备要传给模板的数据
books = [
{'title': 'Flask Web开发实战', 'author': '李辉'},
{'title': 'Python编程从入门到实践', 'author': '埃里克·马瑟斯'}
]
# 第一个参数是模板文件名,后面的参数是传给模板的键值对
return render_template(
'hello.html',
page_title=f'{name}的主页',
user_name=name,
user_age=age,
books=books
)
5.2 模板继承(避免重复写代码)
如果你的网站有多个页面,头部、底部、导航栏都是一样的,那可以用模板继承来减少重复:
- 先创建一个基础模板
base.html,里面放所有页面共用的内容,并用{% block 块名 %}{% endblock %}预留子页面可以修改的位置:
<!-- templates/base.html -->
<!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 %}小站首页{% endblock %} | Flask入门练手</title>
<!-- 后续加静态文件CSS/JS用 -->
</head>
<body>
<header>
<h1>我的Flask小站</h1>
<nav>
<a href="/">首页</a> |
<a href="/about">关于</a>
</nav>
</header>
<!-- 主要内容块,子页面必须覆盖 -->
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2024 道满PythonAI</p>
</footer>
</body>
</html>
- 再创建子模板
child_about.html,继承基础模板并覆盖需要修改的块:
<!-- templates/child_about.html -->
<!-- 第一行必须写继承语句 -->
{% extends "base.html" %}
<!-- 覆盖title块 -->
{% block title %}关于我们{% endblock %}
<!-- 覆盖content块 -->
{% block content %}
<h2>关于我们</h2>
<p>这是一个用Flask搭建的入门练手小站~</p>
{% endblock %}
- 在
app.py里添加路由:
@app.route('/about')
def about():
return render_template('child_about.html')
6. 静态文件管理(CSS/JS/图片)
CSS、JavaScript、图片这些不需要动态生成的文件,Flask会自动从static文件夹(名字必须是static,不能改!)里提供。
6.1 基本使用
- 在
flask-demo目录下新建static文件夹,再在里面建css、js、images子文件夹
- 比如在
static/css里新建style.css:
/* static/css/style.css */
body {
background-color: #f0f2f5;
font-family: 'Microsoft YaHei', sans-serif;
}
h1 {
color: #1890ff;
}
- 在模板里用
url_for('static', filename='子路径/文件名')生成静态文件的URL:
<!-- 修改templates/base.html的head部分 -->
<head>
...
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>
7. 完整练手项目:简易留言板
现在我们把前面学的内容整合起来,做一个可以留言、删除留言的小应用!
7.1 项目结构
flask-demo/
├── app.py # 应用主文件
├── flask_env/ # 虚拟环境(不用管)
├── static/ # 静态文件
│ └── css/
│ └── style.css
└── templates/ # 模板文件
├── base.html
└── index.html
7.2 代码实现
1. 先修改base.html和style.css(可以参考第5、6节的内容,稍微优化一下视觉效果,更像留言板)
2. 然后修改app.py:
from flask import Flask, render_template, request, redirect, url_for, flash
from datetime import datetime
app = Flask(__name__)
# 必须设置SECRET_KEY才能使用flash消息!
# 实际应用中要用随机生成的密钥,不要用硬编码的
app.secret_key = 'your-random-secret-key-here'
# 模拟数据存储(内存里的列表,重启应用数据会清空,学了数据库后可以换成MySQL/SQLite)
messages = []
# 首页:显示留言列表和留言表单
@app.route('/')
def index():
return render_template('index.html', messages=messages)
# 处理新增留言的POST请求
@app.route('/add_message', methods=['POST'])
def add_message():
# 获取表单数据
name = request.form.get('name', '').strip()
content = request.form.get('content', '').strip()
if name and content:
# 添加留言到列表
messages.append({
'id': len(messages) + 1, # 模拟ID
'name': name,
'content': content,
'time': datetime.now().strftime('%Y-%m-%d %H:%M:%S')
})
# flash消息:显示一次就消失的提示
flash('🎉 留言添加成功!', 'success')
else:
flash('⚠️ 昵称和留言内容不能为空!', 'error')
# redirect(url_for('函数名'))跳转到指定路由,避免重复提交表单
return redirect(url_for('index'))
# 处理删除留言的请求
@app.route('/delete/<int:msg_id>')
def delete_message(msg_id):
global messages
# 过滤掉要删除的留言
messages = [msg for msg in messages if msg['id'] != msg_id]
flash('🗑️ 留言删除成功!', 'info')
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
3. 最后创建templates/index.html:
<!-- templates/index.html -->
{% extends "base.html" %}
{% block title %}简易留言板{% endblock %}
{% block content %}
<!-- 显示flash消息 -->
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class="flash-messages">
{% for category, msg in messages %}
<div class="flash {{ category }}">{{ msg }}</div>
{% endfor %}
</div>
{% endif %}
{% endwith %}
<!-- 留言表单 -->
<div class="form-box">
<h3>留下你的足迹 ✍️</h3>
<form action="{{ url_for('add_message') }}" method="post">
<label for="name">昵称:</label>
<input type="text" id="name" name="name" placeholder="请输入昵称" required>
<br><br>
<label for="content">留言:</label>
<textarea id="content" name="content" rows="4" placeholder="请输入留言内容" required></textarea>
<br><br>
<button type="submit">发送</button>
</form>
</div>
<!-- 留言列表 -->
<div class="message-box">
<h3>留言墙 📋</h3>
{% if messages %}
<ul class="message-list">
{% for msg in messages %}
<li class="message-item">
<div class="msg-header">
<span class="msg-name">{{ msg.name }}</span>
<span class="msg-time">{{ msg.time }}</span>
<a href="{{ url_for('delete_message', msg_id=msg.id) }}" class="delete-btn">删除</a>
</div>
<div class="msg-content">{{ msg.content }}</div>
</li>
{% endfor %}
</ul>
{% else %}
<p class="no-msg">暂无留言,快来抢沙发吧!🛋️</p>
{% endif %}
</div>
{% endblock %}
在Python终端里执行下面的命令,生成一个随机的、安全的32位密钥:
```python
import secrets
print(secrets.token_hex(16))
```
把输出的结果替换掉`app.py`里的`app.secret_key`即可。
8. 相关教程
Flask的简洁性使其成为学习Web开发的绝佳入门选择!建议你:
1. 先把本文的留言板跑通,改改样式和功能试试;
2. 再学Flask的扩展(比如Flask-SQLAlchemy操作数据库);
3. 最后尝试做一个更完整的项目(比如个人博客、Todo List)。
总结
通过本文的学习,你已经掌握了Flask的全部核心基础:
- 如何搭建Flask的开发环境(虚拟环境+安装Flask)
- 如何创建和运行第一个Flask应用
- 如何使用路由系统(基本路由、带变量的路由、HTTP方法)
- 如何使用Jinja2模板引擎(变量、条件、循环、继承)
- 如何管理静态文件
- 如何做一个完整的入门练手项目
Flask的灵活性和可扩展性使其适用于各种规模的Web应用,从简单的API到复杂的企业级应用都能胜任!接下来,你可以继续学习Flask的扩展,让你的应用更强大~