<?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>Pallets &#8211; 李辉 / Grey Li</title>
	<atom:link href="https://greyli.com/tag/pallets/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>Pallets &#8211; 李辉 / Grey Li</title>
	<link>https://greyli.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Flask 的 Logo 是什么？</title>
		<link>https://greyli.com/flask-logo/</link>
		<comments>https://greyli.com/flask-logo/#respond</comments>
		<pubDate>Sat, 17 Jul 2021 03:13:04 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[logo]]></category>
		<category><![CDATA[Pallets]]></category>
		<category><![CDATA[考据]]></category>

		<guid isPermaLink="false">https://greyli.com/?p=3853</guid>
		<description><![CDATA[我在连续三年 PyCon China 的三个演讲里，试图以重复三遍的方式来澄清非常普遍的对于 Flask 的  [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>我在连续三年 PyCon China 的三个演讲里，试图以重复三遍的方式来澄清非常普遍的对于 Flask 的 logo 是什么的误解。成效怎么样暂且不说，但是最近发现我其实是在用一个新的误解来替换前一个误解……我一直以为 Flask 的 logo 是用动物角制成用来装火药粉末的容器，即 <a href="https://en.wikipedia.org/wiki/Powder_horn">powder horn</a>，但它其实是用来装饮品的容器，即 <a href="https://en.wikipedia.org/wiki/Drinking_horn">drinking horn</a>（或许可以翻译成「牛角杯」？）。录制<a href="https://greyli.com/flask-talk/">捕蛇者说播客 Ep 30</a> 第一次聊到了这件事，这里再写一篇文章来广而告之，作为对自己传播错误知识的救赎 :P。</p>
<p>这是 Flask 的 logo：</p>
<p><img class="aligncenter" src="https://flask.palletsprojects.com/en/2.0.x/_images/flask-logo.png" alt="Flask: web development, one drop at a time" width="388" height="152" /></p>
<p>因为它的形状，很多人以为 Flask 的 logo 是辣椒：</p>
<p><a href="https://greyli.com/wp-content/uploads/2021/07/hot-pepper.png"><img class="aligncenter size-large wp-image-3861" src="https://greyli.com/wp-content/uploads/2021/07/hot-pepper-1024x991.png" alt="hot-pepper" width="625" height="605" srcset="https://greyli.com/wp-content/uploads/2021/07/hot-pepper-1024x991.png 1024w, https://greyli.com/wp-content/uploads/2021/07/hot-pepper-150x145.png 150w, https://greyli.com/wp-content/uploads/2021/07/hot-pepper-300x290.png 300w, https://greyli.com/wp-content/uploads/2021/07/hot-pepper-624x604.png 624w" sizes="(max-width: 625px) 100vw, 625px" /></a></p>
<p>但从外观上看，它显然更像是 powder horn（而且 powder horn 也叫做 <a href="https://en.wikipedia.org/wiki/Powder_flask">powder flask</a>，再加上它们都像 Flask logo 一样有盖子）：<a href="https://greyli.com/wp-content/uploads/2021/07/powder-horn.png"><img class="aligncenter size-large wp-image-3863" src="https://greyli.com/wp-content/uploads/2021/07/powder-horn-1024x988.png" alt="powder horn" width="625" height="603" srcset="https://greyli.com/wp-content/uploads/2021/07/powder-horn-1024x988.png 1024w, https://greyli.com/wp-content/uploads/2021/07/powder-horn-150x145.png 150w, https://greyli.com/wp-content/uploads/2021/07/powder-horn-300x289.png 300w, https://greyli.com/wp-content/uploads/2021/07/powder-horn-624x602.png 624w" sizes="(max-width: 625px) 100vw, 625px" /></a></p>
<p>尽管看起来很像 powder horn，但是考虑到它的名字和 WSGI（经常被读作 whiskey，威士忌）的隐含关联（类似 Bottle 框架，都是用来装 WSGI 的容器），再加上它标语里的「one drop at a time」，所以它其实是 drinking horn：</p>
<p><a href="https://greyli.com/wp-content/uploads/2021/07/drinking-horn.png"><img class="aligncenter size-large wp-image-3864" src="https://greyli.com/wp-content/uploads/2021/07/drinking-horn-1024x989.png" alt="drinking horn" width="625" height="604" srcset="https://greyli.com/wp-content/uploads/2021/07/drinking-horn-1024x989.png 1024w, https://greyli.com/wp-content/uploads/2021/07/drinking-horn-150x145.png 150w, https://greyli.com/wp-content/uploads/2021/07/drinking-horn-300x290.png 300w, https://greyli.com/wp-content/uploads/2021/07/drinking-horn-624x603.png 624w" sizes="(max-width: 625px) 100vw, 625px" /></a></p>
<p>这一次不会再错了，因为我已经跟 Armin Ronachor（Flask 作者）确认过了：</p>
<blockquote>
<p>Armin Ronachor: it was supposed to be a drinking horn.</p>
</blockquote>
<p>顺便说一下，Flask 及其相关依赖所属的 <a href="https://palletsprojects.com/">Pallets</a> 组织的 logo 是一种木质运载托盘（<a href="https://en.wikipedia.org/wiki/Pallet">wiki</a>），在欧洲被用来运送货物，这里的双关语是「用 pallet 来 ship software」：</p>
<p class="md-end-block md-p"><span class="md-image md-img-loaded" data-src="https://palletsprojects.com/logo-large.png"><img class="aligncenter" src="https://palletsprojects.com/logo-large.png" alt="img" width="372" height="262" /></span></p>
<p>相关链接：</p>
<ul>
<li><a href="https://www.v2ex.com/t/790094">本文在 V2EX 上的讨论</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/flask-logo/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Flask 2.0 版本发布</title>
		<link>https://greyli.com/flask2/</link>
		<comments>https://greyli.com/flask2/#comments</comments>
		<pubDate>Wed, 12 May 2021 05:39:25 +0000</pubDate>
		<dc:creator><![CDATA[李辉]]></dc:creator>
				<category><![CDATA[计算机与编程]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[Flask2]]></category>
		<category><![CDATA[Pallets]]></category>

		<guid isPermaLink="false">https://greyli.com/?p=3728</guid>
		<description><![CDATA[Flask 以及 Flask 依赖的 5 个 Pallets 项目都在今天发布了新的主版本（下面的链接指向各个 [&#8230;]]]></description>
				<content:encoded><![CDATA[
<p>Flask 以及 Flask 依赖的 5 个 <a href="https://palletsprojects.com/">Pallets 项目</a>都在今天发布了新的主版本（下面的链接指向各个项目的主版本变动日志）：</p>
<ul>
<li><a href="https://flask.palletsprojects.com/en/2.0.x/changes#version-2-0-0">Flask 2.0</a></li>
<li><a href="https://werkzeug.palletsprojects.com/en/2.0.x/changes/#version-2-0-0">Werkzeug 2.0</a></li>
<li><a href="https://jinja.palletsprojects.com/en/3.0.x/changes/#version-3-0-0">Jinja 3.0</a></li>
<li><a href="https://click.palletsprojects.com/en/8.0.x/changes/#version-8-0">Click 8.0</a></li>
<li><a href="https://itsdangerous.palletsprojects.com/en/2.0.x/changes/#version-2-0-0">ItsDangerous 2.0</a></li>
<li><a href="https://markupsafe.palletsprojects.com/en/2.0.x/changes/#version-2-0-0">MarkupSafe 2.0</a></li>
</ul>
<p>​你可以使用下面的命令更新 Flask：</p>
<pre class="" lang="bash" spellcheck="false"> pip install -U flask</pre>
<p>如果你使用的国内 PyPI 镜像还没有同步最新版本，可以通过下面的命令临时切换到官方 PyPI 源：</p>
<pre class=""> pip install -U flask -i https://pypi.org/simple/</pre>
<p>这篇文章会介绍一些 Flask 新增的特性，完整的变动可以参考上面各个项目的变动日志。</p>
<h2>三个核心特性</h2>
<p><strong>嵌套蓝本（<a href="https://github.com/pallets/flask/pull/3923">#3923</a>）</strong></p>
<p>对于一个比较大的项目，一般会使用蓝本来组织不同的模块。而如果你的项目非常大，那么嵌套蓝本就可以派上用场了。借助嵌套蓝本支持，你可以在某个蓝本之上再创建多个子蓝本，对项目进行多层模块化组织（而且支持无限嵌套，你可以嵌套很多层）：</p>
<pre class="" lang="python" spellcheck="false"> parent = Blueprint("parent", __name__)  # 创建父蓝本
 child = Blueprint("child", __name__)  # 创建子蓝本
 parent.register_blueprint(child, url_prefix="/child")  # 把子蓝本注册到父蓝本上
 app.register_blueprint(parent, url_prefix="/parent")  # 把父蓝本注册到程序实例上</pre>
<p>这样在生成子蓝本的 URL 时需要传入完整的端点链：</p>
<pre class="" lang="python" spellcheck="false"> url_for('parent.child.create')
 /parent/child/create</pre>
<p>这个特性来源于一个 2012 年创建的 <a href="https://github.com/pallets/flask/issues/593">feature request issue</a>。</p>
<p><strong>基本的 async/await 支持（<a href="https://github.com/pallets/flask/pull/3412">#3412</a>）</strong></p>
<p>Flask 2.0 带来了基本的异步支持，现在你可以定义异步视图（以及异步错误处理函数、异步请求钩子函数）：</p>
<pre class="" lang="python" spellcheck="false"> import asyncio
 from flask import Flask
 ​
 app = Flask(__name__)
 ​
 @app.route('/')
 async def say_hello():
     await asyncio.sleep(1)
     return {'message': 'Hello!'}</pre>
<p>注意要先安装额外依赖：</p>
<pre class="" lang="bash" spellcheck="false"> pip install -U flask[async]</pre>
<p>顺便说一句，如果你在 Windows 上使用 Python 3.8，那么会有一个来自 Python 或 asgiref 的 bug 导致出错：<span spellcheck="false">ValueError: set_wakeup_fd only works in main thread</span>。可以通过下面两种方式（任选一种）处理（具体参考<a href="https://stackoverflow.com/a/67308923/5511849">这个 SO 回答</a>）：</p>
<ul>
<li>升级到 Python 3.9</li>
<li>在你的入口脚本顶部添加临时修复代码：</li>
</ul>
<pre class="" lang="python" spellcheck="false"> # top of the file
 import sys, asyncio
 ​
 if sys.platform == "win32" and (3, 8, 0) &lt;= sys.version_info &lt; (3, 9, 0)::
     asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())</pre>
<p>不过目前只是一个基于 asgiref 的异步实现，作为异步支持的第一步，后续还会进行更多的优化和改进，更多相关信息可以参考<a href="https://flask.palletsprojects.com/en/2.0.x/async-await/">文档</a>。</p>
<p><strong>快捷路由装饰器（<a href="https://github.com/pallets/flask/pull/3907">#3907</a>）</strong></p>
<p>新增了下面的快捷路由装饰器：</p>
<ul>
<li class="md-end-block md-p md-focus"><span class="md-pair-s md-expand" spellcheck="false"><code>app.get()</code></span></li>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>app.post()</code></span></li>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>app.delete()</code></span></li>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>app.put()</code></span></li>
<li class="md-end-block md-p md-focus"><span class="md-pair-s md-expand" spellcheck="false"><code>app.patch()</code></span></li>
</ul>
<p><span class="md-plain md-expand">举例来说，使用 </span><span class="md-pair-s" spellcheck="false"><code>app.post()</code></span><span class="md-plain"> 等同于 </span><span class="md-pair-s" spellcheck="false"><code>app.route(methods=['POST'])</code></span><span class="md-plain md-expand">：</span></p>
<pre class="" lang="python" spellcheck="false"> from flask import Flask
 ​
 app = Flask(__name__)
 ​
 @app.post('/')
 def index():
     return {'message': 'Hello!'}</pre>
<p><span class="md-plain md-expand">注意不要在这些快捷装饰器里传入 </span><span class="md-pair-s" spellcheck="false"><code>methods</code></span><span class="md-plain"> 参数。如果需要在单个视图处理多个方法的请求，使用 </span><span class="md-pair-s" spellcheck="false"><code>app.route()</code></span><span class="md-plain md-expand">。</span></p>
<p>我在某次 pallets 会议上提议添加这些装饰器时一开始是被拒绝的，后来 Phil Jones 创建了 <a href="https://github.com/pallets/flask/pull/3907">#3907</a> 经过二次讨论后才最终合并（被拒绝后我就把当时正在开发的 <a href="https://github.com/greyli/apiflask">APIFlask</a> 从扩展改成了继承 Flask 基类的框架，然后加了这些装饰器）。</p>
<h2>我添加的三个特性</h2>
<p><strong>修复执行 flask run 找不到程序的奇怪设定（<a href="https://github.com/pallets/flask/pull/3560">#3560</a>）</strong></p>
<p>这个像 bug 又像是 feature 的设定我在《<a style="font-size: 1rem;" href="https://greyli.com/a-flask-bug-that-bother-me-two-years/">一个困扰我两年的 Flask「Bug」</a><span style="font-size: 1rem;">》里详细说过，最终终于在两年后修复了。</span></p>
<p><strong>支持在 .flaskenv 和 .env 文件里写中文（<a href="https://github.com/pallets/flask/pull/3932">#3932</a>）</strong></p>
<p>我在《Flask Web 开发实战》第一章介绍 .flaskenv 文件时给了一个示例，演示如何添加注释：</p>
<pre class="">SOME_VAR=1
# 这是注释</pre>
<p>但这个示例没有实际测试……加了中文其实会报错，后来有两次收到读者反馈，最终终于在三年后修复了。</p>
<p><strong>为文档添加命令切换面板（<a href="https://github.com/pallets/flask/pull/3714">#3714</a>）</strong></p>
<p>这个或许算不上特性，不过在我看来是对用户非常友好的变动。除了个别不需要区分操作系统和命令行程序的命令外，我给文档里所有的命令添加了支持切换 Bash/CMD/Powershell 以及 macOS/Linux/Windows 的切换面板（面板的样式后续会有一些<a href="https://github.com/pallets/pallets-sphinx-themes/pull/31">优化</a>）：</p>
<p><img class="aligncenter size-large wp-image-3730" src="https://greyli.com/wp-content/uploads/2021/05/flask-command-tab-1024x324.png" alt="" width="625" height="198" srcset="https://greyli.com/wp-content/uploads/2021/05/flask-command-tab-1024x324.png 1024w, https://greyli.com/wp-content/uploads/2021/05/flask-command-tab-150x47.png 150w, https://greyli.com/wp-content/uploads/2021/05/flask-command-tab-300x95.png 300w, https://greyli.com/wp-content/uploads/2021/05/flask-command-tab-624x198.png 624w, https://greyli.com/wp-content/uploads/2021/05/flask-command-tab.png 1336w" sizes="(max-width: 625px) 100vw, 625px" /></p>
<h2>其他的有用特性</h2>
<ul>
<li class="md-end-block md-p md-focus"><span class="md-plain md-expand">优化了浏览器缓存控制，对 CSS、图片等静态文件做出的变动会在程序重载后立刻更新，不再需要手动清除页面缓存。</span></li>
<li class="md-end-block md-p"><span class="md-plain">Werkzeug 的 multipart 解析（尤其是大文件上传处理）性能提高了 15 倍。</span></li>
<li class="md-end-block md-p"><span class="md-plain">配置对象增加 </span><span class="md-pair-s" spellcheck="false"><code>Config.from_file()</code></span><span class="md-plain"> 方法支持从任意文件加载器导入配置（比如 </span><span class="md-pair-s" spellcheck="false"><code>toml.load</code></span><span class="md-plain">、</span><span class="md-pair-s" spellcheck="false"><code>json.load</code></span><span class="md-plain">），未来会取代 </span><span class="md-pair-s" spellcheck="false"><code>Config.from_json()</code></span><span class="md-plain"> 方法。</span></li>
<li class="md-end-block md-p"><span class="md-plain">在使用环境变量 </span><span class="md-pair-s" spellcheck="false"><code>FLASK_APP</code></span><span class="md-plain"> 指定工厂函数时支持传入关键字参数。</span></li>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>flask shell</code></span><span class="md-plain"> 支持 tab 和历史补全（需要安装 </span><span class="md-pair-s" spellcheck="false"><code>readline</code></span><span class="md-plain">）。</span></li>
<li class="md-end-block md-p md-focus"><span class="md-plain md-expand">CLI 系统优化了找不到程序时的错误处理和错误输出显示，同时修正了 Windows 上的命令行颜色输出。</span></li>
</ul>
<h2>破坏性变动</h2>
<p class="md-end-block md-p md-focus">主要的破坏性变动（breaking change）是意外的把 <code>send_from_directory()</code> 函数的第二个参数名称直接由 <code>filename</code> 重命名为 <code>path</code>，将会在 2.0.1 加回来（<a class=" wrap external" href="https://github.com/pallets/flask/pull/4019" target="_blank" rel="nofollow noopener noreferrer" data-za-detail-view-id="1043">#4019</a>）。</p>
<p>另外 <code>send_file()</code> 函数的三个参数也进行了重命名（旧名称将在 2.1.0 移除）：</p>
<ul>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>attachment_filename</code></span><span class="md-plain"> -&gt; </span><span class="md-pair-s" spellcheck="false"><code>download_name</code></span></li>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>cache_timeout</code></span><span class="md-plain"> -&gt; </span><span class="md-pair-s" spellcheck="false"><code>max_age</code></span></li>
<li class="md-end-block md-p"><span class="md-pair-s" spellcheck="false"><code>add_etags</code></span><span class="md-plain"> -&gt; </span><span class="md-pair-s" spellcheck="false"><code>etag</code></span></li>
</ul>
<h2>其他重要变化</h2>
<ul>
<li>不再支持 Python 2 和 Python 3.5。</li>
<li>所有 Pallets 项目都添加了 type hinting，这意味着更好的 IDE 自动补全体验。</li>
<li>所有仓库的主分支由 master 改为 main。如果你在本地克隆了 Flask 等仓库，可以使用下面的命令来更新：</li>
</ul>
<pre class="" lang="bash" spellcheck="false"> git branch -m master main
 git fetch origin
 git branch -u origin/main main
 git remote set-head origin -a</pre>
<h2>感谢支持</h2>
<p>这次更新对于整个 Pallets 项目来说是一个新的里程碑。接下来还有许多事情要做：FlaskCon 2021 正在准备中，新建立的 Flask 社区工作小组（Flask Community Work Group）正在进行 Flask 文档翻译（如果你对中文翻译感兴趣，可以订阅<a href="https://github.com/greyli/helloflask/discussions/239">这个讨论</a>）、被遗弃扩展收容计划（这是我一直想做的事情）等等。感谢支持，敬请期待！</p>
<p>欢迎通过下列途径关注 Pallets 项目：</p>
<ul>
<li>关注 Twitter <a href="https://twitter.com/PalletsTeam">@PalletsTeam</a></li>
<li>订阅 <a href="https://palletsprojects.com/blog/feed.xml">Pallets 博客 RSS</a></li>
<li>加入 <a href="https://discord.gg/pallets">Pallets Discord 服务器</a></li>
<li>在 <a href="https://github.com/pallets/flask">GitHub</a> 点击 Watch 按钮关注项目动态</li>
</ul>
<p>相关文章：</p>
<ul>
<li><a href="https://palletsprojects.com/blog/flask-2-0-released/">New Major Versions Released! Flask 2.0, Werkzeug 2.0, and more &#8211; Pallets Blog</a></li>
<li><a href="https://www.youtube.com/watch?v=G54QyX_lWo8&amp;t=166s&amp;ab_channel=TalkPython">Flask 2.0 &#8211; Talk Python Podcast</a></li>
<li><a href="https://greyli.com/better-than-typo-fix/">比修 Typo 还简单的开源贡献方式</a></li>
<li><a href="https://greyli.com/what-flask-book-bring-to-the-community/">写作一本技术书，能给一个社区带来哪些改变？</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>https://greyli.com/flask2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
