系列文章

Python 从入门到精通

第 31 / 36 篇

从环境安装和基础语法出发,逐步学习工程实践、自动化、数据处理与 Web 开发。

  1. 01
    Python 怎么装、怎么用
  2. 02
    变量、数字和字符串
  3. 03
    列表:把一组数据放在一起
  4. 04
    元组、集合和字典
  5. 05
    条件判断:让程序做选择
  6. 06
    循环:重复的事交给程序
  7. 07
    函数:把代码整理成可复用的块
  8. 08
    模块与包:拆分你的程序
  9. 09
    输入、输出与字符串格式化
  10. 10
    文件读写:保存程序的数据
  11. 11
    异常处理:程序出错时怎么办
  12. 12
    基础阶段练习:命令行记账本
  13. 13
    类和对象:面向对象入门
  14. 14
    继承、组合与特殊方法
  15. 15
    迭代器与生成器
  16. 16
    列表推导式与生成器表达式
  17. 17
    装饰器:给函数增加能力
  18. 18
    上下文管理器与 with
  19. 19
    类型标注与 dataclass
  20. 20
    正则表达式:从文本中找规律
  21. 21
    日期、时间与时区
  22. 22
    日志与调试
  23. 23
    虚拟环境与依赖管理
  24. 24
    测试:让修改不再提心吊胆
  25. 25
    网络请求:用 Python 调用 API
  26. 26
    网页解析与合规采集
  27. 27
    操作 Excel、CSV 与批量文件
  28. 28
    SQLite:给程序加一个数据库
  29. 29
    数据分析入门:NumPy 与 Pandas
  30. 30
    画图:把数据变得直观
  31. 31
    Flask 入门:做一个小网站正在阅读
  32. 32
    异步编程:同时处理多项任务
  33. 33
    线程、进程与并发选择
  34. 34
    性能分析与优化
  35. 35
    项目结构、配置与发布
  36. 36
    综合项目:从需求到上线

查看整个系列 →

学了这么久,终于到”做出能给别人用的东西”这一步了。这一篇用 Flask 做一个小网站——Python 里最简单好上手的 Web 框架。学完你就能把自己的脚本变成网页服务。

Flask 是什么

Flask 是一个微型 Web 框架:你写 Python 函数,它负责”把网址对应到函数”。用户访问 /,就执行你写的 index() 函数,把结果返回给浏览器。

pip install flask

最小应用:三行代码的网站

创建 app.py

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "你好,南山小站!"

if __name__ == "__main__":
    app.run(debug=True)

运行:

python app.py

浏览器打开 http://127.0.0.1:5000,就能看到”你好,南山小站!”。你已经有一个网站了。

@app.route("/") 是路由装饰器:把 URL 路径和函数绑在一起。访问哪个路径,就执行哪个函数。

路由:多个页面 + 动态参数

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "首页"

@app.route("/about")
def about():
    return "关于我们"

# 动态参数: 是变量,访问 /user/南山 时 name="南山"
@app.route("/user/<name>")
def user(name):
    return f"你好,{name}!"

# 整数参数
@app.route("/post/<int:post_id>")
def post(post_id):
    return f"文章 #{post_id}"

访问 /user/南山 返回”你好,南山!”。一个路由函数就能处理一类 URL。

模板:Jinja2 渲染 HTML

直接返回字符串太简陋,用模板生成完整 HTML。在项目里建 templates/ 目录,放 index.html

<!DOCTYPE html>
<html>
<head>
    <title>南山小站</title>
</head>
<body>
    <h1>{{ title }}</h1>
    <p>今天是 {{ date }},本站有 {{ count }} 篇文章。</p>
    <ul>
        {% for post in posts %}
        <li>{{ post }}</li>
        {% endfor %}
    </ul>
</body>
</html>
from flask import Flask, render_template
from datetime import datetime

app = Flask(__name__)

@app.route("/")
def index():
    return render_template(
        "index.html",
        title="南山小站",
        date=datetime.now().strftime("%Y-%m-%d"),
        count=3,
        posts=["开站了", "阴天", "折腾"],
    )

模板语法(Jinja2):{{ 变量 }} 输出、{% for x in list %} 循环、{% if %} 判断。HTML 和逻辑分离,页面好维护。

表单 POST:接收用户输入

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route("/greet", methods=["GET", "POST"])
def greet():
    if request.method == "POST":
        name = request.form.get("name", "陌生人")   # 取表单数据
        return f"你好,{name}!"
    # GET:显示表单页面
    return """
    <form method="post">
        <input name="name" placeholder="你的名字">
        <button type="submit">打招呼</button>
    </form>
    """

methods=["GET", "POST"] 让一个路由同时处理两种请求;request.form.get() 取表单提交的数据。这就是”用户能交互”的网站了。

重定向和 404

from flask import Flask, redirect, url_for, abort

app = Flask(__name__)

@app.route("/")
def index():
    return redirect(url_for("about"))    # 跳转到 about 页面

@app.route("/about")
def about():
    return "关于页"

@app.route("/post/<int:post_id>")
def post(post_id):
    if post_id > 100:
        abort(404)                       # 触发 404
    return f"文章 {post_id}"

@app.errorhandler(404)
def not_found(e):
    return "页面不存在(404)", 404

部署:让全世界访问

开发模式(debug=True)只适合本地。上线部署的标准组合:gunicorn + nginx

# 1. 服务器上装 gunicorn
pip install gunicorn

# 2. 用 gunicorn 启动(4 个 worker 进程,监听 8000 端口)
gunicorn -w 4 -b 127.0.0.1:8000 app:app

# 3. nginx 配置:把 80 端口转发到 8000(示例)
# server {
#     listen 80;
#     server_name example.com;
#     location / {
#         proxy_pass http://127.0.0.1:8000;
#         proxy_set_header Host $host;
#     }
# }

要点:

  • 别用 debug=True 上线——它会暴露调试器和敏感信息,是安全漏洞
  • 生产用 gunicorn(多进程扛并发),nginx 管静态文件和转发
  • 长期运行用 systemd 或 supervisor 托管,崩了自动重启

实战:天气查询小站

把之前学的串起来——用 requests 查天气,Flask 展示:

# app.py
from flask import Flask, request, render_template
import requests

app = Flask(__name__)

def get_weather(city):
    resp = requests.get(
        f"https://wttr.in/{city}",
        params={"format": "3", "lang": "zh"},
        timeout=10,
    )
    resp.raise_for_status()
    return resp.text.strip()

@app.route("/", methods=["GET", "POST"])
def index():
    result = None
    if request.method == "POST":
        city = request.form.get("city", "敦化")
        try:
            result = get_weather(city)
        except requests.exceptions.RequestException:
            result = "查询失败,稍后再试"
    return render_template("weather.html", result=result)

这个项目把 requests、异常处理、Flask、模板全用上了——学以致用就是这么快。

新手坑

坑 1:debug=True 上线。绝对禁止,安全漏洞 + 性能差。

坑 2:模板文件路径不对。模板必须放在 templates/ 目录(和 app.py 同级),否则 TemplateNotFound。

坑 3:改代码不生效。生产模式(非 debug)下改代码要重启 gunicorn。调试期用 debug=True 自动重载,上线记得关。

小结

  • @app.route("/路径") 把 URL 绑到函数;<变量> 动态参数
  • 模板:templates/ 目录 + Jinja2 语法({{ }} 输出、{% %} 逻辑)
  • 表单:methods=[“GET”,”POST”] + request.form.get()
  • 部署:gunicorn -w 4 -b 127.0.0.1:8000 app:app + nginx 转发
  • 上线关 debug,错误处理用 abort/errorhandler

练习

  1. 把之前的”记账本”改成 Flask 版:首页显示账单列表,表单能添加记录(数据先放内存列表)
  2. 做一个”待办清单”小站:添加、标记完成、删除
  3. 思考:为什么生产环境不能用 debug=True?”调试器 PIN 码”如果被攻击者拿到,他能对你的服务器做什么?