请叫各位大神这是卡西欧手表型号什么型号的?

在Python的Flask框架中构建Web表单的教程
作者:ipython
字体:[ ] 类型:转载 时间:
Flask框架中自带一个Form表单类,通过它的子类来实现表单将相当惬意,这里就为大家带来Python的Flask框架中构建Web表单的教程,需要的朋友可以参考下
尽管Flask的request对象提供的支持足以处理web表单,但依然有许多任务会变得单调且重复。表单的HTML代码生成和验证提交的表单数据就是两个很好的例子。
Flask-WTF扩展使得处理web表单能获得更愉快的体验。该扩展是一个封装了与框架无关的WTForms包的Flask集成。
Flask-WTF和它的依赖集可以通过pip来安装:
(venv) $ pip install flask-wtf
1、跨站请求伪造(CSRF)保护
默认情况下,Flask-WTF保护各种形式对跨站请求伪造(CSRF)攻击。一个CSRF攻击发生在一个恶意网站发送请求给受害者登录的其他网站。
为了实现CSRF保护,Flask-WTF需要应用程序去配置一个加密密钥。Flask-WTF使用这个密钥去生成加密令牌用于验证请求表单数据的真实性。下面将展示如何配置加密密钥。
示例hello.py:Flask-WTF配置
app = Flask(__name__)
app.config['SECRET_KEY'] = 'hard to guess string'
app.config字典通常是框架、扩展或应用程序自身存放配置变量的地方,可以使用标准字典语法添加配置值到app.config中。配置对象提供方法来从文件或环境导入配置值。
SECRET_KEY配置变量作为Flask和一些第三方扩展的通用加密密钥。加密的强度取决于这个变量的值。给你构建的每个应用程序选择不同的密钥,并确保这个字符串不被其他任何人知道。
注:为了提高安全性,密钥应该存储在一个环境变量中,而不是嵌入到代码中。这个会在第7章中描述。
使用Flask-WTF时,每个web表单是由继承自Form类的子类来展现的。该类在表单中定义了一组表单域,每个都表示为一个对象。每个表单域都可以连接到一个或多个validators;validators是一个用于检查用户提交的输入是否合法的函数。
下面的示例展示了一个拥有文本框和提交按钮的简单web表单。
示例hello.py:表单类定义
from flask.ext.wtf import Form
from wtforms import StringField, SubmitField
from wtforms.validators import Required
class NameForm(Form):
name = StringField('What is your name?', validators=[Required()])
submit = SubmitField('Submit')
表单中的域被定义为类的变量,且每个类的变量都指定一个表单域类型对象。在上一个示例中,NameForm表单有一个name文本框和submit提交按钮。StringField类表示一个type="text"属性的&input&标签。SubmitField类表示一个type="submit"属性的&input&标签。表单域构造函数的第一个参数是一个label,在渲染表单到HTML时会使用。
StringField构造函数包含可选参数validators,它定义了一组检查来验证用户提交的数据。Required()验证确保提交的表单域不为空。
注:Flask-WTF扩展定义了表单基类,所以它从flask.ext.wtf导入。表单域、验证都是直接从WTForms包中导入。
下面的表格展示了一组WTForms支持的标准表单域。
表格WTForms标准HTML表单域
下面则展示了一组WTForms内建验证。
&WTForms验证
3、HTML渲染的表单
表单域是可调用的,调用时从模板渲染它们到HTML。假设视图函数传递一个参数名为form的NameForm实例给模板,模板就会生成一个简单的HTML表单,如下所示:
&form method="POST"&
{{ form.name.label }} {{ form.name() }}
{{ form.submit() }}
当然,结果是什么都没有。为了改变表单的外观显示,任何发送给该表单域的参数会被转换为HTML表单域属性;例如,你可以给定表单域id或class属性,然后定义CSS样式:
&form method="POST"&
{{ form.name.label }} {{ form.name(id='my-text-field') }}
{{ form.submit() }}
即使有HTML属性,努力用这种方式渲染表单是非常重要的,所以最好是尽可能的使用Bootstrap自带的一系列表单样式。Flask-Bootstrap使用Bootstrap的预定义表单样式来提供高级的帮助函数来渲染整个Flask-WTF表单,这些操作都只需要一个调用即可完成。使用Flask-Bootstrap,上一个表单可以像下面这样来渲染:
{% import "bootstrap/wtf.html" as wtf %}
{{ wtf.quick_form(form) }}
import指令和常规的Python脚本一样的作用并且允许模板元素被导入并在许多模板中使用。被导入的bootstrap/wtf.html文件,定义了帮助函数使用Bootstrap来渲染Flask-WTF表单。wtf.quick_form()函数传入Flask-WTF表单对象并使用默认Bootstrap样式渲染它。示例4-3展示了完整的hello.py模板。
示例 templates/index.html:使用Flask-WTF和Flask-Bootstrap渲染表单
{% extends "base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
&div class="page-header"&
&h1&Hello, {% if name %}{{ name }}{% else %}Stranger{% endif %}!&/h1&
{{ wtf.quick_form(form) }}
{% endblock %}
目前模板的内容区有两块。第一块是类为page-header的div输出一个问候语。这里使用了模板条件判断语句。在Jinja2中格式为{% if variable %}...{% else %}...{% endif %}。如果判断条件为True则渲染if和else之间的内容。如果判断条件为False则渲染else和endif之间的内容。示例模板会渲染字符串“Hello, Stranger!”当name模板参数未定义的时候。第二块内容使用wtf.quick_form()函数渲染NameForm对象。
4、启动脚本
顶层目录中的manage.py文件用于启动应用。这个脚本会在示例7-8中展示。
示例 manage.py:启动脚本
#!/usr/bin/env python
from app import create_app, db
from app.models import User, Role
from flask.ext.script import Manager, Shell
from flask.ext.migrate import Migrate, MigrateCommand
app = create_app(os.getenv('FLASK_CONFIG') or 'default')
manager = Manager(app)
migrate = Migrate(app, db)
def make_shell_context():
return dict(app=app, db=db, User=User, Role=Role)
manager.add_command("shell", Shell(make_context=make_shell_context))
manager.add_command('db', MigrateCommand)
if __name__ == '__main__':
manager.run()
这个脚本开始于创建应用程序。使用环境变量FLASK_CONFIG,若它已经定义了则从中获取配置;如果没有,则是用默认配置。然后用于Python shell的Flask-Script、Flask-Migrate以及自定义上下文会被初始化。
为了方便,会增加一行执行环境,这样在基于Unix的操作系统上可以通过./manage.py来执行脚本来替代冗长的python manage.py。
5、需求文件
应用程序必须包含requirements.txt文件来记录所有依赖包,包括精确的版本号。这很重要,因为可以在不同的机器上重新生成虚拟环境,例如在生产环境的机器上部署应用程序。这个文件可以通过下面的pip命令自动生成:
(venv) $ pip freeze &requirements.txt
当安装或更新一个包之后最好再更新一下这个文件。以下展示了一个需求文件示例:
Flask==0.10.1
Flask-Bootstrap==3.0.3.1
Flask-Mail==0.9.0
Flask-Migrate==1.1.0
Flask-Moment==0.2.0
Flask-SQLAlchemy==1.0
Flask-Script==0.6.6
Flask-WTF==0.9.4
Jinja2==2.7.1
Mako==0.9.1
MarkupSafe==0.18
SQLAlchemy==0.8.4
WTForms==1.0.5
Werkzeug==0.9.4
alembic==0.6.2
blinker==1.3
itsdangerous==0.23
当你需要完美复制一个虚拟环境的时候,你可以运行以下命令创建一个新的虚拟环境:
(venv) $ pip install -r requirements.txt
当你读到这时,示例requirements.txt文件中的版本号可能已经过时了。如果喜欢你可以尝试用最近发布的包。如果遇到任何问题,你可以随时回退到需求文件中与应用兼容的指定版本。
6、单元测试
这个应用非常小以至于不需要太多的测试,但是作为示例会在示例7-9中展示两个简单的测试定义。
示例 tests/test_basics.py:单元测试
import unittest
from flask import current_app
from app import create_app, db
class BasicsTestCase(unittest.TestCase):
def setUp(self):
self.app = create_app('testing')
self.app_context = self.app.app_context()
self.app_context.push()
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
self.app_context.pop()
def test_app_exists(self):
self.assertFalse(current_app is None)
def test_app_is_testing(self):
self.assertTrue(current_app.config['TESTING'])
编写好的测试使用的是来自于Python标准库中标准的unittest包。setUp()和tearDown()方法在每个测试之前和之后运行,且任何一个方法必须以test_开头作为测试来执行。
建议:如果你想要学习更多使用Python的unittest包来写单元测试的内容,请参阅官方文档。
setUp()方法尝试创建一个测试环境,类似于运行应用程序。首先它创建应用程序配置用于测试并激活上下文。这一步确保测试可以和常规请求一样访问current_app。然后,当需要的时候,可以创建一个供测试使用的全新数据库。数据库和应用程序上下文会在tearDown()方法中被移除。
第一个测试确保应用程序实例存在。第二个测试确保应用程序在测试配置下运行。为了确保tests目录有效,需要在tests目录下增加__init__.py文件,不过该文件可以为空,这样unittest包可以扫描所有模块并定位测试。
建议:如果你有克隆在GitHub上的应用程序,你现在可以运行git checkout 7a来切换到这个版本的应用程序。为了确保你已经安装了所有依赖集,需要运行pip install -r requirements.txt。
为了运行单元测试,可以在manage.py脚本中增加一个自定义的命令。
下面的例子展示如何添加测试命令。
示例 manage.pyt:单元测试启动脚本
def test():
"""Run the unit tests."""
import unittest
tests = unittest.TestLoader().discover('tests')
unittest.TextTestRunner(verbosity=2).run(tests)
<mand装饰器使得它可以很容易的实现自定义命令。被装饰的函数名可以被当做命令名使用,且函数的文档字符串会显示帮助信息。test()函数的执行会调用unittest包中的测试运行器。
单元测试可以像下面这样执行:
(venv) $ python manage.py test
test_app_exists (test_basics.BasicsTestCase) ... ok
test_app_is_testing (test_basics.BasicsTestCase) ... ok
.----------------------------------------------------------------------
Ran 2 tests in 0.001s
7、数据库启动
与单脚本的应用相比,重构后的应用使用不同数据库。
从环境变量中获取的数据库URL作为首选,默认SQLite数据库作为可选。三个配置中的环境变量和SQLite数据库文件名是不一样的。例如,开发配置的URL是从DEV_DATABASE_URL环境变量中获取,如果没有定义则会使用名为data-dev.sqlite的SQLite数据库。
无论数据库URL源的是哪一个,都必须为新的数据库创建数据库表。如果使用了Flask-Migrate来保持迁移跟踪,数据库表可以被创建或更新到最近的版本通过下面的命令:
(venv) $ python manage.py db upgrade
相信与否,已经到了第一部分结束的地方。你现在已经学到了Flask必要的基本要素,但是你不确定如何将这些零散的知识组合在一起形成一个真正的应用程序。第二部分的目的是通过开发一个完整的应用程序来带领你继续前行。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具MVC怎么在当前视图中,传递参数给到另外一个视图?_ASP.NET技巧_
MVC怎么在当前视图中,传递参数给到另外一个视图?
来源:人气:1188
在TransData.cshtml视图中:
&!--在一个视图中,请求另外一个视图,并且将数据传到另外一个视图--&
&!--视图中调用无返回值的方法,需要加上大括号--&
@{ViewBag.ViewTransData="我是视图TransData中定义的数据,将要被传递到LoadViewBySelf视图中";}
@{Html.RenderPartial("LoadViewBySelf");}
请求LoadViewBySelf视图,并传递数据到其中:
ViewBag.Title = "LoadViewBySelf";}
&h2&LoadViewBySelf&/h2&@ViewBag.ViewTransDataTTT@ViewData["ViewTransDataTTT"]
然后运行TransData视图,得到:
查看源文件可以看到:
在视图中调用有返回值的方法,就不用加上大括号了;
@{Html.RenderPartial("LoadViewBySelf");}
&!--在视图中调用有返回值的方法,不用加大括号--&
@Html.TextBox("testname");
优质网站模板快速入门 & Flask 0.10.1 documentation
迫切希望上手?本文提供了一个很好的 Flask 介绍。假设你已经安装 Flask,
如果还没有安装话,请浏览下
一个最小的应用
一个最小的应用看起来像这样:
from flask import Flask
app = Flask(__name__)
@app.route(&#39;/&#39;)
def hello_world():
return &#39;Hello World!&#39;
if __name__ == &#39;__main__&#39;:
把它保存成 hello.py (或者类似的文件),然后用 Python 解释器运行它。确保你的应用不叫做 flask.py,
因为这会与 Flask 本身冲突。
$ python hello.py
* Running on http://127.0.0.1:5000/
现在浏览 ,你会看到你的 Hello World 问候。
那么这段代码做了什么?
首先我们导入了类
。这个类的实例化将会是我们的 WSGI 应用。第一个参数是应用模块的名称。
如果你使用的是单一的模块(就如本例),第一个参数应该使用 __name__。因为取决于如果它以单独应用启动或作为模块导入,
名称将会不同 ( '__main__' 对应于实际导入的名称)。获取更多的信息,请阅读
接着,我们创建一个该类的实例。我们传递给它模块或包的名称。这样 Flask 才会知道去哪里寻找模板、静态文件等等。
我们使用装饰器
告诉 Flask 哪个 URL 才能触发我们的函数。
定义一个函数,该函数名也是用来给特定函数生成 URLs,并且返回我们想要显示在用户浏览器上的信息。
最后我们用函数
启动本地服务器来运行我们的应用。if __name__ == '__main__':
确保服务器只会在该脚本被 Python 解释器直接执行的时候才会运行,而不是作为模块导入的时候。
请按 control-C 来停止服务器。
外部可见服务器
当你运行服务器,你会注意到它只能从你自己的计算机上访问,网络中其它任何的地方都不能访问。
这是因为默认情况下,调试模式,应用中的一个用户可以执行你计算机上的任意 Python 代码。
如果你关闭 debug 或者信任你所在网络上的用户,你可以让你的服务器对外可用,只要简单地改变方法
的调用像如下这样:
app.run(host=&#39;0.0.0.0&#39;)
这让你的操作系统去监听所有公开的 IP。
方法是十分适用于启动一个本地开发服务器,但是你需要在修改代码后手动重启服务器。
这样做并不好,Flask 能做得更好。如果启用了调试支持,在代码修改的时候服务器能够自动加载,
并且如果发生错误,它会提供一个有用的调试器。
有两种方式开启调式模式。一种是在应用对象上设置标志位:
app.debug = True
或者作为 run 的一个参数传入:
app.run(debug=True)
两种方法效果是一样的。
尽管交互式调试器不能在分叉( forking )环境上工作(这使得它几乎不可能在生产服务器上使用),
它依然允许执行任意代码。这使它成为一个巨大的安全风险,因此它 绝对不能用于生成环境。
运行中的调试器的截图:
是不是还有其它的调试器?请查看 。
现代 Web 应用程序有优雅的 URLs。这能够帮助人们记住 URLs,这点在面向使用慢网络连接的移动设备的应用上有用。
如果用户不必通过点击首页而直接访问想要的页面,很可能他们会喜欢这个页面而且下次再次访问。
正如上面所说,
装饰器是用于把一个函数绑定到一个 URL 上。这有些基本的例子:
@app.route(&#39;/&#39;)
def index():
return &#39;Index Page&#39;
@app.route(&#39;/hello&#39;)
def hello():
return &#39;Hello World&#39;
但是不仅如此!你可以动态地构造 URL 的特定部分,也可以在一个函数上附加多个规则。
为了给 URL 增加变量的部分,你需要把一些特定的字段标记成 &variable_name&。这些特定的字段将作为参数传入到你的函数中。当然也可以指定一个可选的转换器通过规则 &converter:variable_name&。
这里有一些不错的例子:
@app.route(&#39;/user/&username&&#39;)
def show_user_profile(username):
# show the user profile for that user
return &#39;User %s&#39; % username
@app.route(&#39;/post/&int:post_id&&#39;)
def show_post(post_id):
# show the post with the given id, the id is an integer
return &#39;Post %d&#39; % post_id
存在如下转换器:
同 int 一样,但是接受浮点数
和默认的相似,但也接受斜线
唯一 URLs / 重定向行为
Flask 的 URL 规则是基于 Werkzeug 的 routing 模块。
该模块背后的想法是基于 Apache 和早期的 HTTP 服务器定下先例确保优雅和唯一的 URL。
以这两个规则为例:
@app.route(&#39;/projects/&#39;)
def projects():
return &#39;The project page&#39;
@app.route(&#39;/about&#39;)
def about():
return &#39;The about page&#39;
虽然它们看起来确实相似,但它们结尾斜线的使用在 URL 定义 中不同。
第一种情况中,规范的 URL 指向 projects 尾端有一个斜线。
这种感觉很像在文件系统中的文件夹。访问一个结尾不带斜线的 URL 会被 Flask 重定向到带斜线的规范URL去。
然而,第二种情况的 URL 结尾不带斜线,类似 UNIX-like 系统下的文件的路径名。
访问结尾带斜线的 URL 会产生一个 404 “Not Found” 错误。
当用户访问页面时忘记结尾斜线时,这个行为允许关联的 URL 继续工作,
并且与 Apache 和其它的服务器的行为一致。另外,URL 会保持唯一,有助于避免搜索引擎索引同一个页面两次。
如果它可以匹配 URL,那么 Flask 能够生成它们吗?当然 Flask 能够做到。你可以使用函数
来针对一个特定的函数构建一个 URL。它能够接受函数名作为第一参数,以及一些关键字参数,
每一个关键字参数对应于 URL 规则的变量部分。未知变量部分被插入到 URL 中作为查询参数。这里有些例子:
&&& from flask import Flask, url_for
&&& app = Flask(__name__)
&&& @app.route(&#39;/&#39;)
... def index(): pass
&&& @app.route(&#39;/login&#39;)
... def login(): pass
&&& @app.route(&#39;/user/&username&&#39;)
... def profile(username): pass
&&& with app.test_request_context():
print url_for(&#39;index&#39;)
print url_for(&#39;login&#39;)
print url_for(&#39;login&#39;, next=&#39;/&#39;)
print url_for(&#39;profile&#39;, username=&#39;John Doe&#39;)
/login?next=/
/user/John%20Doe
(这里也使用了
方法,下面会给出解释。这个方法告诉 Flask 表现得像是在处理一个请求,即使我们正在通过 Python 的 shell 交互。
请看下面的解释。 )。
为什么你愿意构建 URLs 而不是在模版中硬编码?这里有三个好的理由:
反向构建通常比硬编码更具备描述性。更重要的是,它允许你一次性修改 URL,
而不是到处找 URL 修改。
构建 URL 能够显式地处理特殊字符和 Unicode 转义,因此你不必去处理这些。
如果你的应用不在 URL 根目录下(比如,在
/myapplication 而不在 /),
将会适当地替你处理好。
HTTP (也就说 web 应用协议)有不同的方法来访问 URLs。默认情况下,路由只会响应 GET 请求,
但是能够通过给
装饰器提供 methods 参数来改变。这里是些例子:
@app.route(&#39;/login&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def login():
if request.method == &#39;POST&#39;:
do_the_login()
show_the_login_form()
如果使用 GET 方法,HEAD 方法将会自动添加进来。你不必处理它们。也能确保 HEAD 请求
(文档在 HTTP 协议里面描述) 要求来处理, 因此你完全可以忽略这部分 HTTP 规范。
同样地,自从 Flask 0.6 后,OPTIONS 也能自动为你处理。
也许你并不清楚 HTTP 方法是什么?别担心,这里有一个 HTTP 方法的快速入门以及为什么它们重要:
HTTP 方法(通常也称为“谓词”)告诉服务器客户端想要对请求的页面 做 什么。下面这些方法是比较常见的:
浏览器通知服务器只 获取 页面上的信息并且发送回来。这可能是最常用的方法。
浏览器告诉服务器获取信息,但是只对 头信息 感兴趣,不需要整个页面的内容。
应用应该处理起来像接收到一个 GET 请求但是不传递实际内容。在 Flask 中你完全不需要处理它,
底层的 Werkzeug 库会为你处理的。
浏览器通知服务器它要在 URL 上 提交 一些信息,服务器必须保证数据被存储且只存储一次。
这是 HTML 表单通常发送数据到服务器的方法。
同 POST 类似,但是服务器可能触发了多次存储过程,多次覆盖掉旧值。现在你就会问这有什么用,
有许多理由需要如此去做。考虑下在传输过程中连接丢失:在这种情况下浏览器 和服务器之间的系统可能安全地第二次接收请求,而不破坏其它东西。对于 POST 是不可能实现的,因为
它只会被触发一次。
移除给定位置的信息。
给客户端提供一个快速的途径来指出这个 URL 支持哪些 HTTP 方法。从 Flask 0.6 开始,自动实现了它。
现在比较有兴趣的是在 HTML4 和 XHTML1,表单只能以 GET 和 POST 方法来提交到服务器。在 JavaScript 和以后的 HTML 标准中也能使用其它的方法。同时,HTTP 最近变得十分流行,浏览器不再是唯一使用 HTTP 的客户端。比如,许多版本控制系统使用 HTTP。
动态的 web 应用同样需要静态文件。CSS 和 JavaScript 文件通常来源于此。理想情况下,
你的 web 服务器已经配置好为它们服务,然而在开发过程中 Flask 能够做到。
只要在你的包中或模块旁边创建一个名为 static 的文件夹,在应用中使用 /static 即可访问。
给静态文件生成 URL ,使用特殊的 'static' 端点名:
url_for(&#39;static&#39;, filename=&#39;style.css&#39;)
这个文件应该存储在文件系统上称为 static/style.css。
在 Python 中生成 HTML 并不好玩,实际上是相当繁琐的,因为你必须自行做好 HTML 转义以保持应用程序的安全。
由于这个原因,Flask 自动为你配置好
你可以使用方法
来渲染模版。所有你需要做的就是提供模版的名称以及你想要作为关键字参数传入模板的变量。这里有个渲染模版的简单例子:
from flask import render_template
@app.route(&#39;/hello/&#39;)
@app.route(&#39;/hello/&name&&#39;)
def hello(name=None):
return render_template(&#39;hello.html&#39;, name=name)
Flask 将会在 templates 文件夹中寻找模版。因此如果你的应用是个模块,这个文件夹在模块的旁边,如果它是一个包,那么这个文件夹在你的包里面:
Case 1: 一个模块:
/application.py
/templates
/hello.html
Case 2: 一个包:
/application
/__init__.py
/templates
/hello.html
对于模板,你可以使用 Jinja2 模板的全部功能。详细信息查看官方的
这里是一个模版的例子:
&!doctype html&
&title&Hello from Flask&/title&
{% if name %}
&h1&Hello {{ name }}!&/h1&
{% else %}
&h1&Hello World!&/h1&
{% endif %}
在模版中你也可以使用 ,
对象,也能使用函数
模版继承是十分有用的。如果想要知道模版继承如何工作的话,请阅读文档
。基本的模版继承使得某些特定元素(如标题,导航和页脚)在每一页成为可能。
自动转义是开启的,因此如果 name 包含 HTML,它将会自动转义。如果你信任一个变量,并且你知道它是安全的
(例如一个模块把 wiki 标记转换到 HTML ),你可以用 Markup 类或 |safe 过滤器在模板中标记它是安全的。
在 Jinja 2 文档中,你会见到更多例子。
这是一个 Markup 类如何工作的基本介绍:
&&& from flask import Markup
&&& Markup(&#39;&strong&Hello %s!&/strong&&#39;) % &#39;&blink&hacker&/blink&&#39;
Markup(u&#39;&strong&Hello &blink&hacker&/blink&!&/strong&&#39;)
&&& Markup.escape(&#39;&blink&hacker&/blink&&#39;)
Markup(u&#39;&blink&hacker&/blink&&#39;)
&&& Markup(&#39;&em&Marked up&/em& & HTML&#39;).striptags()
u&#39;Marked up \xbb HTML&#39;
Changed in version 0.5: 自动转义不再在所有模版中启用。模板中下列后缀的文件会触发自动转义:.html, .htm,
.xml, .xhtml。从字符串加载的模板会禁用自动转义。
接收请求数据
对于 web 应用来说,对客户端发送给服务器的数据做出反应至关重要。在 Flask 中由全局对象
来提供这些信息。如果你有一定的 Python 经验,你会好奇这个对象怎么可能是全局的,并且 Flask 是怎么还能保证线程安全。
答案是上下文作用域:
局部上下文
如果你想要了解它是如何工作以及如何用它实现测试,请阅读本节,否则请跳过本节。
Flask 中的某些对象是全局对象,但不是通常的类型。这些对象实际上是给定上下文的局部对象的代理。
虽然很拗口,但实际上很容易理解。
想象下线程处理的上下文。一个请求传入,web 服务器决定产生一个新线程(或者其它东西,
底层对象比线程更有能力处理并发系统)。当 Flask 开始它内部请求处理时,它认定当前线程是活动的上下文并绑定当前的应用和 WSGI 环境到那 个上下文(线程)。它以一种智能的方法来实现,以致一个应用可以调用另一个应用而不会中断。
所以这对你意味着什么了?如果你是做一些类似单元测试的事情否则基本你可以完全忽略这种情况。
你会发现依赖于请求对象的代码会突然中断,因为没有请求对象。解决方案就是自己创建一个请求并把它跟上下文绑定。
针对单元测试最早的解决方案是使用
上下文管理器。结合 with 声明,它将绑定一个测试请求来进行交互。这里是一个例子:
from flask import request
with app.test_request_context(&#39;/hello&#39;, method=&#39;POST&#39;):
# now you can do something with the request until the
# end of the with block, such as basic assertions:
assert request.path == &#39;/hello&#39;
assert request.method == &#39;POST&#39;
另一个可能性就是传入整个 WSGI 环境到
from flask import request
with app.request_context(environ):
assert request.method == &#39;POST&#39;
请求对象在 API 章节中描述,这里我们不再详细涉及(请看 )。这里对一些最常见的操作进行概述。
首先你需要从 flask 模块中导入它:
from flask import request
当前请求的方法可以用 method 属性来访问。你可以用 form 属性来访问表单数据
(数据在 POST 或者 PUT 中传输)。这里是上面提及到两种属性的完整的例子:
@app.route(&#39;/login&#39;, methods=[&#39;POST&#39;, &#39;GET&#39;])
def login():
error = None
if request.method == &#39;POST&#39;:
if valid_login(request.form[&#39;username&#39;],
request.form[&#39;password&#39;]):
return log_the_user_in(request.form[&#39;username&#39;])
error = &#39;Invalid username/password&#39;
# the code below this is executed if the request method
# was GET or the credentials were invalid
return render_template(&#39;login.html&#39;, error=error)
如果在 form 属性中不存在上述键值会发生些什么?在这种情况下会触发一个特别的 。
你可以像捕获标准的
来捕获它,如果你不这样去做,会显示一个 HTTP 400 Bad Request 错误页面。
所以很多情况下你不需要处理这个问题。
你可以用 args 属性来接收在 URL ( ?key=value ) 中提交的参数:
searchword = request.args.get(&#39;key&#39;, &#39;&#39;)
我们推荐使用 get 来访问 URL 参数或捕获 KeyError ,因为用户可能会修改 URL,
向他们显示一个 400 bad request 页面不是用户友好的。
想获取请求对象的完整的方法和属性清单,请参阅
你能够很容易地用 Flask 处理文件上传。只要确保在你的 HTML 表单中不要忘记设置属性 enctype=&multipart/form-data&,
否则浏览器将不传送文件。
上传的文件是存储在内存或者文件系统上一个临时位置。你可以通过请求对象中 files 属性访问这些文件。
每个上传的文件都会存储在这个属性字典里。它表现得像一个标准的 Python file 对象,但是它同样具有
方法,该方法允许你存储文件在服务器的文件系统上。
这儿是一个简单的例子展示如何工作的:
from flask import request
@app.route(&#39;/upload&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def upload_file():
if request.method == &#39;POST&#39;:
f = request.files[&#39;the_file&#39;]
f.save(&#39;/var/www/uploads/uploaded_file.txt&#39;)
如果你想要知道在上传到你的应用之前在客户端的文件名称,你可以访问
属性。但请记住永远不要信任这个值,因为这个值可以伪造。如果你想要使用客户端的文件名来在服务器上存储文件,
把它传递到 Werkzeug 提供给你的
from flask import request
from werkzeug import secure_filename
@app.route(&#39;/upload&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def upload_file():
if request.method == &#39;POST&#39;:
f = request.files[&#39;the_file&#39;]
f.save(&#39;/var/www/uploads/&#39; + secure_filename(f.filename))
一些更好的例子,请查看
属性来访问 cookies。你能够用响应对象的
来设置 cookies。请求对象中的
属性是一个客户端发送所有的 cookies 的字典。
如果你要使用会话(sessions),请不要直接使用 cookies 相反用 Flask 中的 ,Flask 已经在 cookies 上增加了一些安全细节。
读取 cookies:
from flask import request
@app.route(&#39;/&#39;)
def index():
username = request.cookies.get(&#39;username&#39;)
# use cookies.get(key) instead of cookies[key] to not get a
# KeyError if the cookie is missing.
存储 cookies:
from flask import make_response
@app.route(&#39;/&#39;)
def index():
resp = make_response(render_template(...))
resp.set_cookie(&#39;username&#39;, &#39;the username&#39;)
return resp
注意 cookies 是在响应对象中被设置。由于通常只是从视图函数返回字符串, Flask 会将其转换为响应对象。
如果你要显式地这么做,你可以使用
函数接着修改它。
有时候你可能要在响应对象不存在的地方设置 cookie。利用
模式使得这种情况成为可能。
为此也可以参阅 。
重定向和错误
函数重定向用户到其它地方。能够用
函数提前中断一个请求并带有一个错误代码。
这里是一个它们如何工作的例子:
from flask import abort, redirect, url_for
@app.route(&#39;/&#39;)
def index():
return redirect(url_for(&#39;login&#39;))
@app.route(&#39;/login&#39;)
def login():
abort(401)
this_is_never_executed()
这是一个相当无意义的例子因为用户会从主页重定向到一个不能访问的页面( 401意味着禁止访问),
但是它说明了重定向如何工作。
默认情况下,每个错误代码会显示一个黑白错误页面。如果你想定制错误页面,可以使用
from flask import render_template
@app.errorhandler(404)
def page_not_found(error):
return render_template(&#39;page_not_found.html&#39;), 404
注意到 404 是在
调用之后。告诉 Flask 该页的错误代码应是 404 ,
即没有找到。默认的 200 被假定为:一切正常。
一个视图函数的返回值会被自动转换为一个响应对象。如果返回值是一个字符串,它被转换成一个响应主体是该字符串,错误代码为 200 OK ,媒体类型为 text/html 的响应对象。
Flask 把返回值转换成响应对象的逻辑如下:
如果返回的是一个合法的响应对象,它会被从视图直接返回。
如果返回的是一个字符串,响应对象会用字符串数据和默认参数创建。
如果返回的是一个元组而且元组中元素能够提供额外的信息。这样的元组必须是 (response, status,
headers) 形式且至少含有一个元素。 status 值将会覆盖状态代码,headers 可以是一个列表或额外的消息头值字典。
如果上述条件均不满足,Flask 会假设返回值是一个合法的 WSGI 应用程序,并转换为一个请求对象。
如果你想要获取在视图中得到的响应对象,你可以用函数
想象你有这样一个视图:
@app.errorhandler(404)
def not_found(error):
return render_template(&#39;error.html&#39;), 404
你只需要用
封装返回表达式,获取结果对象并修改,然后返回它:
@app.errorhandler(404)
def not_found(error):
resp = make_response(render_template(&#39;error.html&#39;), 404)
resp.headers[&#39;X-Something&#39;] = &#39;A value&#39;
return resp
除了请求对象,还有第二个称为
对象允许你在不同请求间存储特定用户的信息。
这是在 cookies 的基础上实现的,并且在 cookies 中使用加密的签名。这意味着用户可以查看 cookie 的内容,
但是不能修改它,除非它知道签名的密钥。
要使用会话,你需要设置一个密钥。这里介绍会话如何工作:
from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
@app.route(&#39;/&#39;)
def index():
if &#39;username&#39; in session:
return &#39;Logged in as %s&#39; % escape(session[&#39;username&#39;])
return &#39;You are not logged in&#39;
@app.route(&#39;/login&#39;, methods=[&#39;GET&#39;, &#39;POST&#39;])
def login():
if request.method == &#39;POST&#39;:
session[&#39;username&#39;] = request.form[&#39;username&#39;]
return redirect(url_for(&#39;index&#39;))
return &#39;&#39;&#39;
&form action=&& method=&post&&
&p&&input type=text name=username&
&p&&input type=submit value=Login&
&#39;&#39;&#39;
@app.route(&#39;/logout&#39;)
def logout():
# remove the username from the session if it&#39;s there
session.pop(&#39;username&#39;, None)
return redirect(url_for(&#39;index&#39;))
# set the secret key.
keep this really secret:
app.secret_key = &#39;A0Zr98j/3yX R~XHH!jmN]LWX/,?RT&#39;
这里提到的
可以在你不使用模板引擎的时候做转义(如同本例)。
怎样产生一个好的密钥
随机的问题在于很难判断什么是真随机。一个密钥应该足够随机。你的操作系统可以基于一个密码随机生成器来生成漂亮的随机值,这个值可以用来做密钥:
&&& import os
&&& os.urandom(24)
&#39;\xfd{H\xe5&\x95\xf9\xe3\x96.5\xd1\x01O&!\xd5\xa2\xa0\x9fR&\xa1\xa8&#39;
把这个值复制粘贴到你的代码,你就搞定了密钥。
使用基于 cookie 的会话需注意: Flask 会将你放进会话对象的值序列化到 cookie。如果你试图寻找一个跨请求不能存留的值,
cookies 确实是启用的,并且你不会获得明确的错误信息,检查你页面请求中 cookie 的大小,并与 web 浏览器所支持的大小对比。
好的应用和用户界面全部是关于反馈。如果用户得不到足够的反馈,他们可能会变得讨厌这个应用。Flask 提供了一个
真正的简单的方式来通过消息闪现系统给用户反馈。消息闪现系统基本上使得在请求结束时记录信息并在下一个
(且仅在下一个)请求中访问。通常结合模板布局来显示消息。
方法来闪现一个消息,使用
能够获取消息,
也能用于模版中。针对一个完整的例子请查阅 。
New in version 0.3.
有时候你会处于一种你处理的数据应该是正确的,然而实际上并不正确的状况。比如你可能有一些客户端代码,
代码向服务器发送一个 HTTP 请求但是显然它是畸形的。这可能是由于用户篡改数据,或客户端代码失败。
大部分时候针对这一情况返回 400 Bad Request 就可以了,但是有时候不行因为代码必须继续工作。
你可能仍然想要记录发生什么不正常事情。这时候日志就派上用处。从 Flask 0.3 开始日志记录是预先配置好的。
这里有一些日志调用的例子:
app.logger.debug(&#39;A value for debugging&#39;)
app.logger.warning(&#39;A warning occurred (%d apples)&#39;, 42)
app.logger.error(&#39;An error occurred&#39;)
是一个标准的日志类
,因此更多的信息请
查阅官方文档 。
整合 WSGI 中间件
如果你想给你的应用添加 WSGI 中间件,你可以封装内部 WSGI 应用。例如如果你想使用 Werkzeug 包中的某个中间件来应付 lighttpd 中的 bugs,你可以这样做:
from werkzeug.contrib.fixers import LighttpdCGIRootFix
app.wsgi_app = LighttpdCGIRootFix(app.wsgi_app)
部署到 Web 服务器
准备好部署你的新 Flask 应用?你可以立即部署到托管平台来完成快速入门,以下是向小项目提供免费的方案:
你可以托管 Flask 应用的其它选择:
如果你管理你自己的主机并且想要自己运行,请参看 。

我要回帖

更多关于 卡西欧型号怎么看 的文章

 

随机推荐