<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Watchlist &#8211; 李辉 / Grey Li</title>
	<atom:link href="https://greyli.com/tag/watchlist/feed/" rel="self" type="application/rss+xml" />
	<link>https://greyli.com</link>
	<description>一个编程和写作爱好者的在线记事本</description>
	<lastBuildDate>Thu, 06 Nov 2025 11:36:11 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.9.26</generator>

<image>
	<url>https://greyli.com/wp-content/uploads/2025/03/avatar-500-compressed-144x144.jpg</url>
	<title>Watchlist &#8211; 李辉 / Grey Li</title>
	<link>https://greyli.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>《Flask 入门教程》第 2 章：Hello, Flask!</title>
		<link>https://greyli.com/flask-tutorial-chapter-2-hello-flask/</link>
		<comments>https://greyli.com/flask-tutorial-chapter-2-hello-flask/#comments</comments>
		<pubDate>Tue, 11 Dec 2018 05:25:45 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[Flask 入门教程]]></category>
		<category><![CDATA[Watchlist]]></category>

		<guid isPermaLink="false">http://greyli.com/?p=2020</guid>
		<description><![CDATA[追溯到最初，Flask 诞生于 Armin Ronacher 在 2010 年愚人节开的一个玩笑。后来，它逐渐 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>
	追溯到最初，Flask 诞生于 Armin Ronacher 在 2010 年愚人节开的一个玩笑。后来，它逐渐发展成为一个成熟的 Python Web 框架，越来越受到开发者的喜爱。目前它在 GitHub 上是 Star 数量最多的 Python Web 框架，没有之一。
</p>
<p>
	Flask 是典型的微框架，作为 Web 框架来说，它仅保留了核心功能：<strong>请求响应处理</strong>和<strong>模板渲染</strong>。这两类功能分别由 Werkzeug（WSGI 工具库）完成和 Jinja（模板渲染库）完成，因为 Flask 包装了这两个依赖，我们暂时不用深入了解它们。
</p>
<h2>
	主页<br />
</h2>
<p>
	这一章的主要任务就是为我们的程序编写一个简单的主页。主页的 URL 一般就是根地址，即&nbsp;<code>/</code>。当用户访问根地址的时候，我们需要返回一行欢迎文字。这个任务只需要下面几行代码就可以完成：
</p>
<pre>
from flask import Flask
app = Flask(__name__)

@app.route(&#39;/&#39;)
def hello():
    return &#39;Welcome to My Watchlist!&#39;</pre>
<p>
	按照惯例，我们把程序保存为 app.py，确保当前目录是项目的根目录，然后在命令行窗口执行&nbsp;<code>flask run</code>&nbsp;命令启动程序（按下 Control + C 可以退出）：
</p>
<pre>
$ flask run
* Serving Flask app &quot;app.py&quot;
* Environment: production
  WARNING: Do not use the development server in a production environment.
  Use a production WSGI server instead.
* Debug mode: off
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)</pre>
<p>
	现在打开浏览器，访问&nbsp;<a href="http://localhost:5000/" rel="nofollow">http://localhost:5000</a>&nbsp;即可访问我们的程序主页，并看到我们在程序里返回的问候语，如下图所示：
</p>
<p>
	<a href="https://github.com/greyli/flask-tutorial/blob/master/chapters/images/2-1.png" rel="noopener noreferrer" target="_blank"><img alt="2-1" src="https://github.com/greyli/flask-tutorial/raw/master/chapters/images/2-1.png" /></a>
</p>
<p>
	执行&nbsp;<code>flask run</code>&nbsp;命令时，Flask 会使用内置的开发服务器来运行程序。这个服务器默认监听本地机的 5000 端口，也就是说，我们可以通过在地址栏输入&nbsp;<a href="http://127.0.0.1:5000/" rel="nofollow">http://127.0.0.1:5000</a>&nbsp;或是&nbsp;<a href="http://localhost:5000/" rel="nofollow">http://localhost:5000</a>&nbsp;访问程序。
</p>
<p>
	<strong>注意</strong>&nbsp;内置的开发服务器只能用于开发时使用，部署上线的时候要换用性能更好的服务器，我们会在最后一章学习。
</p>
<h2>
	解剖时间<br />
</h2>
<p>
	下面我们来分解这个 Flask 程序，了解它的基本构成。
</p>
<p>
	首先我们从&nbsp;<code>flask</code>&nbsp;包导入&nbsp;<code>Flask</code>&nbsp;类，通过实例化这个类，创建一个程序对象&nbsp;<code>app</code>：
</p>
<pre>
from flask import Flask
app = Flask(__name__)</pre>
<p>
	接下来，我们要注册一个处理函数，这个函数是处理某个请求的处理函数，Flask 官方把它叫做视图函数（view funciton），你可以理解为&ldquo;<strong>请求处理函数</strong>&rdquo;。
</p>
<p>
	所谓的&ldquo;注册&rdquo;，就是给这个函数戴上一个装饰器帽子。我们使用&nbsp;<code>app.route()</code>&nbsp;装饰器来为这个函数绑定对应的 URL，当用户在浏览器访问这个 URL 的时候，就会触发这个函数，获取返回值，并把返回值显示到浏览器窗口：
</p>
<pre>
@app.route(&#39;/&#39;)
def hello():
    return &#39;Welcome to My Watchlist!&#39;</pre>
<p>
	填入&nbsp;<code>app.route()</code>&nbsp;装饰器的第一个参数是 URL 规则字符串，这里的&nbsp;<code>/</code>指的是根地址。
</p>
<p>
	我们只需要写出相对地址，主机地址、端口号等都不需要写出。所以说，这里的&nbsp;<code>/</code>&nbsp;对应的是主机名后面的路径部分，完整 URL 就是&nbsp;<a href="http://localhost:5000/%E3%80%82%E5%A6%82%E6%9E%9C%E6%88%91%E4%BB%AC%E8%BF%99%E9%87%8C%E5%AE%9A%E4%B9%89%E7%9A%84" rel="nofollow">http://localhost:5000/。如果我们这里定义的</a>&nbsp;URL 规则是&nbsp;<code>/hello</code>，那么完整 URL 就是&nbsp;<a href="http://localhost:5000/hello" rel="nofollow">http://localhost:5000/hello</a>&nbsp;。
</p>
<p>
	整个请求的处理过程如下所示：
</p>
<ol>
<li>
		当用户在浏览器地址栏访问这个地址，在这里即&nbsp;<a href="http://localhost:5000/" rel="nofollow">http://localhost:5000/</a>
	</li>
<li>
		服务器解析请求，发现请求 URL 匹配的 URL 规则是&nbsp;<code>/</code>，因此调用对应的处理函数&nbsp;<code>hello()</code>
	</li>
<li>
		获取&nbsp;<code>hello()</code>&nbsp;函数的返回值，处理后返回给客户端（浏览器）
	</li>
<li>
		浏览器接受响应，将其显示在窗口上
	</li>
</ol>
<p>
	<strong>提示</strong>&nbsp;在 Web 程序的语境下，虽然客户端可能有多种类型，但在本书里通常是指浏览器。
</p>
<h2>
	程序发现机制<br />
</h2>
<p>
	如果你把上面的程序保存成其他的名字，比如 hello.py，接着执行&nbsp;<code>flask run</code>&nbsp;命令会返回一个错误提示。这是因为 Flask 默认会假设你把程序存储在名为 app.py 或 wsgi.py 的文件中。如果你使用了其他名称，就要设置系统环境变量&nbsp;<code>FLASK_APP</code>&nbsp;来告诉 Flask 你要启动哪个程序。
</p>
<p>
	Flask 通过读取这个文件对应的模块寻找要运行的程序实例，你可以把它设置成下面这些值：
</p>
<ul>
<li>
		模块名
	</li>
<li>
		Python 导入路径
	</li>
<li>
		文件目录路径
	</li>
</ul>
<h2>
	管理环境变量<br />
</h2>
<p>
	现在在启动 Flask 程序的时候，我们通常要和两个环境变量打交道：<code>FLASK_APP</code>&nbsp;和&nbsp;<code>FLASK_ENV</code>。因为我们的程序现在的名字是 app.py，暂时不需要设置&nbsp;<code>FLASK_APP</code>；<code>FLASK_ENV</code>&nbsp;用来设置程序运行的环境，默认为&nbsp;<code>production</code>。在开发时，我们需要开启调试模式（debug mode）。调试模式可以通过将系统环境变量&nbsp;<code>FLASK_ENV</code>&nbsp;设为&nbsp;<code>development</code>&nbsp;来开启。调试模式开启后，当程序出错，浏览器页面上会显示错误信息；代码出现变动后，程序会自动重载。
</p>
<p>
	为了不用每次打开新的终端会话都要设置环境变量，我们安装用来管理系统环境变量的 python-dotenv：
</p>
<pre>
$ pipenv install python-dotenv</pre>
<p>
	当 python-dotenv 安装后，Flask 会从项目根目录的 .flaskenv 和 .env 文件读取环境变量并设置。我们分别使用文本编辑器创建这两个文件，或是使用更方便的&nbsp;<code>touch</code>&nbsp;命令创建：
</p>
<pre>
$ touch .env .flaskenv</pre>
<p>
	.flaskenv 用来存储 Flask 命令行系统相关的公开环境变量；而 .env 则用来存储敏感数据，不应该提交进Git仓库，我们把 .env 添加到 .gitignore 文件的结尾（新建一行）来让 Git 忽略它。你可以使用编辑器执行这个操作：
</p>
<pre>
.env</pre>
<p>
	在新创建的 .flaskenv 文件里，我们写入一行&nbsp;<code>FLASK_ENV=development</code>&nbsp;，将环境变量&nbsp;<code>FLASK_ENV</code>&nbsp;的值设为&nbsp;<code>development</code>，以便开启调试模式：
</p>
<pre>
FLASK_ENV=development</pre>
<h2>
	实验时间<br />
</h2>
<p>
	在这个小节，我们可以通过做一些实验，来扩展和加深对本节内容的理解。
</p>
<h3>
	修改视图函数返回值<br />
</h3>
<p>
	首先，你可以自由修改视图函数的返回值，比如：
</p>
<pre>
@app.route(&#39;/&#39;)
def hello():
    return u&#39;欢迎来到我的 Watchlist！&#39;</pre>
<p>
	返回值作为响应的主体，默认会被浏览器作为 HTML 格式解析，所以我们可以添加一个 HTML 元素标记：
</p>
<pre>
@app.route(&#39;/&#39;)
def hello():
    return &#39;&lt;h1&gt;Hello Totoro!&lt;/h1&gt;&lt;img src=&quot;http://helloflask.com/totoro.gif&quot;&gt;&#39;</pre>
<p>
	保存修改后，只需要在浏览器里刷新页面，你就会看到页面上的内容也会随之变化。
</p>
<p>
	<a href="https://github.com/greyli/flask-tutorial/blob/master/chapters/images/2-2.png" rel="noopener noreferrer" target="_blank"><img alt="2-2" src="https://github.com/greyli/flask-tutorial/raw/master/chapters/images/2-2.png" /></a>
</p>
<h3>
	修改 URL 规则<br />
</h3>
<p>
	另外，你也可以自由修改传入&nbsp;<code>app.route</code>&nbsp;装饰器里的 URL 规则字符串，但要注意以斜线&nbsp;<code>/</code>&nbsp;作为开头。比如：
</p>
<pre>
@app.route(&#39;/home&#39;)
def hello():
    return &#39;Welcome to My Watchlist!&#39;</pre>
<p>
	保存修改，这时刷新浏览器，则会看到一个 404 错误提示，提示页面未找到（Page Not Found）。这是因为视图函数的 URL 改成了&nbsp;<code>/home</code>，而我们刷新后访问的地址仍然是旧的&nbsp;<code>/</code>。如果我们把访问地址改成&nbsp;<a href="http://localhost:5000/home%EF%BC%8C%E5%B0%B1%E4%BC%9A%E6%AD%A3%E7%A1%AE%E7%9C%8B%E5%88%B0%E8%BF%94%E5%9B%9E%E5%80%BC%E3%80%82" rel="nofollow">http://localhost:5000/home，就会正确看到返回值。</a>
</p>
<p>
	一个视图函数也可以绑定多个 URL，这通过附加多个装饰器实现，比如：
</p>
<pre>
@app.route(&#39;/&#39;)
@app.route(&#39;/index&#39;)
@app.route(&#39;/home&#39;)
def hello():
    return &#39;Welcome to My Watchlist!&#39;</pre>
<p>
	现在无论是访问&nbsp;<a href="http://localhost:5000/%E3%80%81http://localhost:5000/home" rel="nofollow">http://localhost:5000/、http://localhost:5000/home</a>&nbsp;还是&nbsp;<a href="http://localhost:5000/index" rel="nofollow">http://localhost:5000/index</a>&nbsp;都可以看到返回值。
</p>
<p>
	在前面，我们之所以把传入&nbsp;<code>app.route</code>&nbsp;装饰器的参数称为 URL 规则，是因为我们也可以在 URL 里定义变量部分。比如下面这个视图函数会处理所有类似&nbsp;<code>/user/&lt;name&gt;</code>&nbsp;的请求：
</p>
<pre>
@app.route(&#39;/user/&lt;name&gt;&#39;)
def user_page():
    return &#39;User page&#39;</pre>
<p>
	不论你访问&nbsp;<a href="http://localhost:5000/user/greyli%EF%BC%8C%E8%BF%98%E6%98%AF" rel="nofollow">http://localhost:5000/user/greyli，还是</a>&nbsp;<a href="http://localhost:5000/user/peter%EF%BC%8C%E6%8A%91%E6%88%96%E6%98%AF" rel="nofollow">http://localhost:5000/user/peter，抑或是</a>&nbsp;<a href="http://localhost:5000/user/%E7%94%B2" rel="nofollow">http://localhost:5000/user/甲</a>，都会触发这个函数。通过下面的方式，我们也可以在视图函数里获取到这个变量值：
</p>
<pre>
@app.route(&#39;/user/&lt;name&gt;&#39;)
def user_page(name):
    return &#39;User: %s&#39; % name</pre>
<h3>
	修改视图函数名？<br />
</h3>
<p>
	最后一个可以修改的部分就是视图函数的名称了。首先，视图函数的名字是自由定义的，和 URL 规则无关。和定义其他函数或变量一样，只需要让它表达出所要处理页面的含义即可。
</p>
<p>
	除此之外，它还有一个重要的作用：作为代表某个路由的端点（endpoint），同时用来生成 URL。对于程序内的 URL，为了避免手写，Flask 提供了一个&nbsp;<code>url_for</code>&nbsp;函数来生成 URL，它接受的第一个参数就是端点值，默认为视图函数的名称：
</p>
<pre>
from flask import url_for

...

@app.route(&#39;/&#39;)
def hello():
    return &#39;Hello&#39;

@app.route(&#39;/user/&lt;name&gt;&#39;)
def user_page(name):
    return &#39;User: %s&#39; % name

@app.route(&#39;/test&#39;)
def test_url_for():
	# 下面是一些调用示例：
    print(url_for(&#39;hello&#39;))  # 输出：/
    # 注意下面两个调用是如何生成包含 URL 变量的 URL 的
    print(url_for(&#39;user_page&#39;, name=&#39;greyli&#39;))  # 输出：/user/greyli
    print(url_for(&#39;user_page&#39;, name=&#39;peter&#39;))  # 输出：/user/peter
    print(url_for(&#39;test_url_for&#39;))  # 输出：/test
    # 下面这个调用传入了多余的关键字参数，它们会被作为查询字符串附加到 URL 后面。
    print(url_for(&#39;test_url_for&#39;, num=2))  # 输出：/test?num=2
    return &#39;Test page&#39;</pre>
<p>
	实验过程中编写的代码可以删掉，也可以保留，但记得为根地址返回一行问候，这可是我们这一章的任务。
</p>
<h2>
	本章小结<br />
</h2>
<p>
	这一章我们为程序编写了主页，同时学习了 Flask 视图函数的基本编写方式。结束前，让我们提交代码：
</p>
<pre>
$ git add .
$ git commit -m &quot;Add minimal home page&quot;
$ git push</pre>
<p>
	为了保持简单，我们统一在章节最后一次提交所有改动。在现实世界里，通常会根据需要分为多个 commit；同样的，这里使用&nbsp;<code>-m</code>&nbsp;参数给出简单的提交信息。在现实世界里，你可能需要撰写更完整的提交信息。
</p>
<p>
	<strong>提示</strong> 你可以在 GitHub 上查看本书示例程序的对应 commit：<a href="https://github.com/greyli/watchlist/commit/eca06dcdf682dfa2883a8632814e4c65b6eae141" spellcheck="false">eca06dc</a>。
</p>
<h2>
	进阶提示<br />
</h2>
<ul>
<li>
		如果你使用 Python 2.7，为了使程序正常工作，需要在脚本首行添加编码声明&nbsp;<code># -*- coding: utf-8-*-</code>&nbsp;，并在包含中文的字符串前面添加&nbsp;<code>u</code>&nbsp;前缀。本书中对于包含中文的字符串均添加了&nbsp;<code>u</code>&nbsp;前缀，这在 Python 3 中并不需要。
	</li>
<li>
		对于 URL 变量，Flask 还支持在 URL 规则字符串里对变量设置处理器，对变量进行预处理。比如&nbsp;<code>/user/&lt;int:number&gt;</code>&nbsp;会将 URL 中的 number 部分处理成整型，同时这个变量值接收传入数字。
	</li>
<li>
		因为 Flask 的上下文机制，有一些变量和函数（比如&nbsp;<code>url_for</code>函数）只能在特定的情况下才能正确执行，比如视图函数内。我们先暂时不用纠结，后面再慢慢了解。
	</li>
<li>
		名字以&nbsp;<code>.</code>&nbsp;开头的文件默认会被隐藏，执行&nbsp;<code>ls</code>&nbsp;命令时会看不到它们，这时你可以使用&nbsp;<code>ls -f</code>&nbsp;命令来列出所有文件。
	</li>
<li>
		了解 HTTP 基本知识将会有助于你了解 Flask 的工作原理。
	</li>
<li>
		阅读文章<a href="https://tutorial.djangogirls.org/zh/how_the_internet_works/" rel="nofollow">《互联网是如何工作的》</a>。
	</li>
<li>
		阅读文章<a href="https://zhuanlan.zhihu.com/p/42231394" rel="nofollow">《从HTTP请求 &#8211; 响应循环探索Flask的基本工作方式》</a>。
	</li>
<li>
		如果你是<a href="http://helloflask.com/book/" rel="nofollow">《Flask Web 开发实战》</a>的读者，这部分的进阶内容可以在第 1 章《初识 Flask》和第 2 章《HTTP 和 Flask》找到。
	</li>
<li>
		本书主页 &amp; 相关资源索引：<a data-editable="true" data-offset-key="eh3t9-1-0" href="http://helloflask.com/tutorial" target="_blank">http://helloflask.com/tutorial</a>。
	</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/flask-tutorial-chapter-2-hello-flask/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
