🧪 第1章 建立最基础的应用程序
📄 一句话概括

一个网页请求要做三件事:拿到数据、决定用哪张页面、把数据填进页面。 MVT 就是把这三件事分给三个地方,改一头不用动另一头。 Flask 里的 V 是视图函数,它干的是 MVC 里 Controller 的活——名字别混。

📝 本章和前面几章的关系

从这一章起正式写代码。教材第 1 章是全书的地基,八篇覆盖 1.1 到 1.6 六节。 本篇先把分层讲清,后面七篇一样样落地:应用、配置、路由、模板、表单、消息、会话。

一、一次请求里发生了什么

浏览器请求 /books。 Flask 找到对应的视图函数,函数决定要哪些数据,再挑一张模板,把数据塞进去渲染成 HTML, 最后包成一个响应发回去。 这条路线上有三个可以独立更换的零件:数据从哪来、用哪张页面、页面长什么样。 分开的理由只有一个:它们的变更频率不一样。数据来源半年改一次,页面样式一周改三次, 混在一起就是天天互相踩。

二、Model:数据长什么样

Model 是最容易被误解的一层。它不是数据库表,是「数据在程序里长什么样」。 第 1 章还没有数据库,Model 就是一个普通类:有 title、price 两个属性。 第 2 章接上 SQLAlchemy 之后,同一个位置换成继承 db.Model 的类, 它的职责没变——只不过属性从内存搬到了表里。

所以现在别急着学 ORM,先把「Model 是一个带属性的对象」记住。后面换成数据库模型时, 模板那一层一个字都不用改。

三、View:取数据、挑模板

视图函数是唯一「知道全貌」的地方:它调 Model 拿数据,调 render_template 指定模板, 再把数据当参数传给模板。 三行代码,对应三件事:

@app.route("/books")
def books():
    return render_template("show.html", books=BOOKS)

render_template 的第一个参数是模板文件名(相对模板目录), 后面的关键字参数一个个变成模板里的变量名。 函数返回的不是 HTML 字符串,是一个响应对象。render_template 只是把 HTML 装进去而已。

四、Template:只管长相

模板里可以写循环、判断、过滤器,但不该做业务判断。 「这本书打几折」是业务,「打折标签用什么颜色」才是模板的事。 判断标准很简单:这条逻辑换个页面还用得上吗?用得上就该在视图里算好再传进去。 教材在 1.1 节特别提醒:模板里塞太多逻辑,最后会变成另一种没人敢改的代码。

五、为什么叫 MVT 不叫 MVC

MVC 里的角色 在 Flask 里落到哪
Model Model,没变
View Template,只管长相
Controller 视图函数,但它在 Flask 里被叫作 View

所以 Flask 的 V 和 MVC 的 V 不是同一个东西。看到「视图」两个字,先想清楚说的是函数还是页面。 Django 也自称 MVT,用的是同一套命名。 这不是谁抄谁,是两边都不想让「控制器」这个词出现——Flask 里根本没有那个类。

六、动手 Demo:MVT:把一件事拆成三层

这一节的 Demo 用一个最小号的 MVT 把三层串起来:一个类当 Model,一个函数当 View, 一个模板文件当 Template。 然后往列表里塞一本书,看同一个模板怎么自动多出一行。

class Book:
    def __init__(self, title, price):
        self.title, self.price = title, price

BOOKS = [Book("Flask 实战", 89), Book("Python 入门", 69)]

@app.route("/books")
def books():
    return render_template("show.html", books=BOOKS)

# show.html 里:
# <h1>{{ books|length }} 本书</h1>
# {% for b in books %}<li>{{ b.title }}</li>{% endfor %}

实跑输出:

--------------------------------------------------------------------
MVT:把一件事拆成三层
--------------------------------------------------------------------

  ① 三层各自管什么
  --------------------------------------------------------------------

| 层 | 这次用的是什么 | 只管一件事 |
|---|---|---|
| Model | Book 类加 BOOKS 列表 | 数据长什么样 |
| View | books() 函数 | 取哪些数据、给哪个模板 |
| Template | show.html | 长什么样、怎么循环 |

  ! Flask 里的 V 其实是「视图函数」,它同时干了控制器那份活:既决定拿什么数据,也决定交给谁渲染。

  ② 真请求一次,看它拼出什么
  --------------------------------------------------------------------
  GET /books -> 200,Content-Type text/html; charset=utf-8
  <h1>2 本书</h1>
  <ul>

    <li>Flask 实战 89</li>

    <li>Python 入门 69</li>

  </ul>
  2 是 len(BOOKS) 算出来的,书名列是 for 循环铺出来的——模板里没有一条写死的书名。

  ③ 换数据不用改模板
  --------------------------------------------------------------------
  往列表里再塞一本,同一个请求再来一次:
  <h1>3 本书</h1>
  ! 这就是 MVT 的分工价值:数据和长相分开,改一头不用动另一头。

  ④ 名字千万别混
  --------------------------------------------------------------------

| MVC 里的角色 | 在 Flask 里落到哪 |
|---|---|
| MVC 的 C(Controller) | MVT 里没有这个位置 |
| MVC 的 V(View) | MVT 的 T(Template),只管长相 |
| —— | MVT 的 V(View)干的是 MVC 里 Controller 的活 |

  教材 1.1 节专门解释过这件事:Django 和 Flask 都叫自己 MVT,但那个 V 指的是「视图函数」,
  不是「视图模板」。
  所以看到「视图」两个字,先想清楚说的是函数还是页面——这是新手第一个混淆点。

「2 本书」那个 2 是模板里用 length 过滤器算出来的,不是写死的。 塞进第三本书后重发同一个请求,标题自动变成 3——模板一个字没改。 最后那张表专门理清 MVC 与 MVT 的错位,这是读 Django 文档时最容易绕晕的一段。

30 秒实验

  1. 把 BOOKS 清空,看 for 循环一个都不进时页面渲染成什么样。
  2. 在模板里加一个 {% if books %},写出「还没有书」的空状态。
  3. 想一想:如果「按价格排序」这件事,该放在视图里还是模板里?为什么?

常见误区

  1. 在模板里查数据库:模板里能跑代码,但不该碰数据层,否则换数据源时每张页面都要改。
  2. 把 HTML 拼在视图函数里:等于把 Template 那层删了,改一次样式就要动 Python 代码。
  3. 以为 MVT 的 V 是页面:它是函数,真正管长相的是 T。
  4. Model 里塞业务逻辑:「打几折」这类规则放进模型,换个场景(比如批发)就复用不了。
自测三问(点开对答案) 1. 视图函数在这三层里为什么特殊? —— 只有它同时知道另外两层:既调 Model 取数据,又指定模板并传参。 2. Flask 的 View 和 MVC 的 View 差在哪? —— MVC 的 View 是页面,Flask 的 View 是函数,干的是 Controller 的活。 3. 模板里该不该写业务判断? —— 不该。判断「换张页面还用不用」——复用不了的就该在视图里算好。

分层讲完了,下一篇动手写第一个能跑的应用,顺带把除错模式到底多给了什么量出来。

相关笔记