Flask 简明教程

Flask - Quick Guide

Flask – Overview

What is Web Framework?

Web 应用程序框架或简单的 Web 框架代表了一组库和模块,它使 Web 应用程序开发人员能够编写应用程序,而不必考虑低级细节(例如协议、线程管理等)。

What is Flask?

Flask 是用 Python 编写的 Web 应用程序框架。它是由 Armin Ronacher 开发的,他领导着一个名为 Pocco 的国际 Python 爱好者团体。Flask 基于 Werkzeug WSGI 工具包和 Jinja2 模板引擎。这两个都是 Pocco 项目。

WSGI

Web 服务器网关接口 (WSGI)已被采纳为 Python Web 应用程序开发的标准。WSGI 是 Web 服务器和 Web 应用程序之间通用接口的规范。

Werkzeug

它是 WSGI 工具包,能实现请求、响应对象和其他实用程序功能。这样便可以在其基础上构建 Web 框架。Flask 框架将 Werkzeug 用作其中一个基础。

Jinja2

Jinja2 是 Python 的一个流行模板引擎。Web 模板系统将模板与特定数据源结合以呈现动态 Web 页面。

Flask 通常被称为微框架。它旨在保持应用程序内核简单且可扩展。Flask 没有用于处理数据库的内置抽象层,也没有表单验证支持。相反,Flask 支持扩展来向应用程序添加此类功能。本教程的后面部分将讨论一些流行的 Flask 扩展。

Flask – Environment

Prerequisite

通常需要 Python 2.6 或更高版本才能安装 Flask。尽管 Flask 及其依赖项可与 Python 3 配合良好 (Python 3.3 及更高版本),但许多 Flask 扩展都不支持它。因此,建议在 Python 2.7 上安装 Flask。

Install virtualenv for development environment

virtualenv 是一个虚拟 Python 环境构建程序。它帮助用户并行创建多个 Python 环境。因此,它可以避免不同版本库之间的兼容性问题。

以下命令可安装 virtualenv

pip install virtualenv

此命令需要管理员权限。在 Linux/Mac OS 上,添加 sudo pip 前。如果使用的是 Windows,请以管理员身份登录。在 Ubuntu 上,可以使用其软件包管理器来安装 virtualenv

Sudo apt-get install virtualenv

安装后,会在文件夹中创建一个新的虚拟环境。

mkdir newproj
cd newproj
virtualenv venv

要在 Linux/OS X 激活相应环境,请使用以下内容 -

venv/bin/activate

Windows 上,可以使用以下内容

venv\scripts\activate

现在我们可以准备在此环境中安装 Flask。

pip install Flask

可直接运行以上命令,无需用于系统级安装的虚拟环境。

Flask – Application

为了检测 Flask 的安装情况,请在编辑器中输入以下代码作为 Hello.py

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
   return 'Hello World'

if __name__ == '__main__':
   app.run()

在项目中导入 flask 模块是强制性的。Flask 类的对象是我们的 WSGI 应用程序。

Flask 构造器将 current module (name) 的名称作为参数。

Flask 类的 route() 函数是一个装饰器,它告诉应用程序哪个 URL 应调用关联函数。

app.route(rule, options)
  1. rule 参数表示与函数绑定的 URL。

  2. options 是转发给底层 Rule 对象的参数列表。

原文中的URL ‘/’ 与函数 hello_world() 关联绑定。因此,当在浏览器中打开网络服务器的主页时,该函数的输出数据将被渲染出来。

最后,Flask 类中的 run() 方法将应用程序运行于本地开发服务器上。

app.run(host, port, debug, options)

所有参数都是可选的

Sr.No.

Parameters & Description

1

host 要监听的主机。默认值为 127.0.0.1 (Localhost)。可以将其设置为‘0.0.0.0’以使服务器能够对外网服务

2

port Defaults to 5000

3

debug 默认为 false。如果设置为 True,将提供调试信息

4

options 将提交至底层 Werkzeug 服务器。

上述 Python 脚本是通过 Python shell 执行的。

Python Hello.py

Python shell 中显示的信息表明你

* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

在浏览器中打开上述 URL (localhost:5000)‘Hello World’ 消息将显示于其上。

Debug mode

通过调用 run() 方法启动一个 Flask 应用程序。然而,在应用程序的开发阶段,每次代码有变化时,都应手动重新启动应用程序。为了避免这种情况带来的不便,可以启用 debug support 。之后,如果代码有变化,服务器将自行重新载入。它还将提供一个有用的调试器,用于追踪应用程序中存在的任何错误。

启用 Debug 模式需要在运行或向 run() 方法传递 debug 参数之前,将 application 对象的 debug 属性设置为 True

app.debug = True
app.run()
app.run(debug = True)

Flask – Routing

现代网络框架使用路由技术来帮助用户记住应用程序 URL。这对于直接访问目标页面非常有用,而无需从主页进行导航。

Flask 中的 route() 装饰器用于将 URL 与一个函数进行绑定。例如 −

@app.route(‘/hello’)
def hello_world():
   return ‘hello world’

在这里,URL ‘/hello’ 规则被绑定至 hello_world() 函数。因此,如果用户访问 http://localhost:5000/hello URL, hello_world() 函数的输出数据将在浏览器中渲染出来。

某个应用程序对象中的 add_url_rule() 函数还可以用于将 URL 与函数进行绑定,如同在上述示例中使用 route() 的情况。

以下表示法也可以实现装饰器的目的 −

def hello_world():
   return ‘hello world’
app.add_url_rule(‘/’, ‘hello’, hello_world)

Flask – Variable Rules

通过在规则参数中添加可变部分,可以动态构建一个 URL。该可变部分被标记为 <variable-name> 。将它作为关键字参数传递给该规则关联的函数。

在以下的示例中, route() 装饰器的规则参数中包含 <name> 可变部分,连接至 URL ‘/hello’ 。因此,如果将 http://localhost:5000/hello/TutorialsPoint 输入为浏览器中的 URL ,那么 ‘TutorialPoint’ 将被作为参数提供给 hello() 函数。

from flask import Flask
app = Flask(__name__)

@app.route('/hello/<name>')
def hello_name(name):
   return 'Hello %s!' % name

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

保存上述脚本 hello.py ,接着从 Python shell 运行。接下来,打开浏览器,并输入 URL http://localhost:5000/hello/TutorialsPoint.

浏览器中会显示以下输出。

Hello TutorialsPoint!

除了默认的字符串变量部分,还可以使用以下转换器构造规则 -

Sr.No.

Converters & Description

1

int accepts integer

2

float For floating point value

3

path 接受用作目录分隔符的斜杠

在以下代码中,将使用所有这些构造器。

from flask import Flask
app = Flask(__name__)

@app.route('/blog/<int:postID>')
def show_blog(postID):
   return 'Blog Number %d' % postID

@app.route('/rev/<float:revNo>')
def revision(revNo):
   return 'Revision Number %f' % revNo

if __name__ == '__main__':
   app.run()

从 Python Shell 运行上述代码。在浏览器中访问 URL http://localhost:5000/blog/11

给定的数字被用作 show_blog() 函数的参数。浏览器显示以下输出 -

Blog Number 11

在浏览器中输入这个 URL - http://localhost:5000/rev/1.1

revision() 函数将浮点数作为参数。浏览器窗口中会显示以下结果 -

Revision Number 1.100000

Flask 的 URL 规则基于 Werkzeug’s 路由模块。这会确保形成的 URL 唯一并且基于 Apache 规定的优先级。

考虑在以下脚本中定义的规则 −

from flask import Flask
app = Flask(__name__)

@app.route('/flask')
def hello_flask():
   return 'Hello Flask'

@app.route('/python/')
def hello_python():
   return 'Hello Python'

if __name__ == '__main__':
   app.run()

这两个规则看起来很相似,但第二个规则中使用了结尾斜杠 (/) 。结果,它变成了规范 URL。因此,使用 /python/python/ 会返回相同输出。然而,在第一个规则的情况下, /flask/ URL 会产生 404 Not Found 页面。

Flask – URL Building

url_for() 函数对于为特定函数动态构建 URL 非常有用。此函数接收函数名称作为第一个参数,并接收一个或多个关键字参数,每个都对应着 URL 的变量部分。

以下脚本展示了 url_for() 函数的用法。

from flask import Flask, redirect, url_for
app = Flask(__name__)

@app.route('/admin')
def hello_admin():
   return 'Hello Admin'

@app.route('/guest/<guest>')
def hello_guest(guest):
   return 'Hello %s as Guest' % guest

@app.route('/user/<name>')
def hello_user(name):
   if name =='admin':
      return redirect(url_for('hello_admin'))
   else:
      return redirect(url_for('hello_guest',guest = name))

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

上述脚本有一个函数 user(name) ,它接收 URL 中传递给它的参数的值。

User() 函数检查收到的参数是否与 ‘admin’ 匹配。如果匹配,则使用 url_for() 将应用程序重新定向到 hello_admin() 函数,否则将把收到的参数作为 guest 参数传递到 hello_guest() 函数。

保存上述代码并从 Python shell 运行。

打开浏览器并输入 URL 为 − http://localhost:5000/user/admin

浏览器中的应用程序响应为 −

Hello Admin

在浏览器中输入以下 URL − http://localhost:5000/user/mvl

应用程序响应现在更改为 −

Hello mvl as Guest

Flask – HTTP methods

Http 协议是万维网中数据通信的基础。此协议中定义了不同方法才能从指定 URL 检索数据。

下表总结了不同的 http 方法 −

Sr.No.

Methods & Description

1

GET 以未加密形式向服务器发送数据。最常见的方法。

2

HEAD 与 GET 相同,但没有响应正文

3

POST 用于将 HTML 表单数据发送至服务器。通过 POST 方法接收的数据不会被服务器缓存。

4

PUT 用上传的内容替换目标资源的所有当前表示形式。

5

DELETE 删除由 URL 给出的目标资源的所有当前表示形式

默认情况下,Flask 路由响应 GET 请求。然而,可以通过向 route() 装饰器提供 methods 参数来更改此首选项。

为了说明如何在 URL 路由中使用 POST 方法,首先让我们创建一个 HTML 表单,并使用 POST 方法将表单数据发送至 URL。

将以下脚本保存为 login.html

<html>
   <body>
      <form action = "http://localhost:5000/login" method = "post">
         <p>Enter Name:</p>
         <p><input type = "text" name = "nm" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
   </body>
</html>

现在在 Python shell 中输入以下脚本。

from flask import Flask, redirect, url_for, request
app = Flask(__name__)

@app.route('/success/<name>')
def success(name):
   return 'welcome %s' % name

@app.route('/login',methods = ['POST', 'GET'])
def login():
   if request.method == 'POST':
      user = request.form['nm']
      return redirect(url_for('success',name = user))
   else:
      user = request.args.get('nm')
      return redirect(url_for('success',name = user))

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

在开发服务器开始运行后,在浏览器中打开 login.html ,在文本字段中输入 name,然后单击 Submit

post method example

表单数据通过 form 标记的动作子句 POST 至 URL。

http://localhost/login 映射至 login() 函数。由于服务器通过 POST 方法接收了数据,因此可通过以下方式获取从表单数据中获取的“nm”参数值:

user = request.form['nm']

它作为变量部分传递至 ‘/success’ URL。浏览器在窗口中显示 welcome 消息。

welcome message

login.html 中将方法参数更改为 ‘GET’ ,并在浏览器中再次将其打开。服务器上收到的数据通过 GET 方法。现在可通过以下方式获取“nm”参数值:

User = request.args.get(‘nm’)

此处, args 是包含表单参数及其对应值的列表对的字典对象。与之前一样,与“nm”参数对应的值传递给“/success”URL。

Flask – Templates

可以以 HTML 形式返回绑定至某个 URL 的函数的输出。例如,在以下脚本中, hello() 函数将使用附加了 <h1> 标记的 ‘Hello World’ 呈现。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
   return '<html><body><h1>Hello World</h1></body></html>'

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

但是,从 Python 代码中生成 HTML 内容很麻烦,尤其当需要放置变量数据和 Python 语言元素(如条件语句或循环)时。这需要频繁地转义 HTML。

这正是我们可以利用 Flask 所基于的 Jinja2 模板引擎的地方。可以使用 render_template() 函数呈现 HTML 文件,而不从函数返回硬编码的 HTML。

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
   return render_template(‘hello.html’)

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

Flask 会尝试在模板文件夹中查找 HTML 文件,该文件夹与该脚本存在的文件夹相同。

  1. Application folder Hello.pytemplates hello.html

术语 ‘web templating system’ 涉及设计 HTML 脚本,可在其中动态插入变量数据。Web 模板系统包含一个模板引擎、某种数据源和一个模板处理器。

Flask 使用 Jinja2 模板引擎。Web 模板包含 HTML 语法,其中插入用于变量和表达式(在这些情况下是 Python 表达式)的占位符,模板呈现时将替换为值。

以下代码作为 hello.html 保存到模板文件夹中。

<!doctype html>
<html>
   <body>

      <h1>Hello {{ name }}!</h1>

   </body>
</html>

接下来,从 Python shell 运行以下脚本。

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/hello/<user>')
def hello_name(user):
   return render_template('hello.html', name = user)

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

在开发服务器开始运行后,打开浏览器并输入 URL,如下所示: http://localhost:5000/hello/mvl

URL 的 variable 部分插入到 {{ name }} 占位符中。

web templating system example

Jinja2 模板引擎使用以下分隔符转义 HTML。

  1. {% …​ %} 用于语句

  2. {{ …​ }},表示输出到模板的表达式

  3. {# …​ #},表示未包含在模板输出中的注释

  4. = … ##,表示行语句

在以下示例中,演示了模板中的条件语句用法。指向 hello() 函数的 URL 规则接受整数参数。它传到 hello.html 模板。在其内部,比较收到的数字值(分数)(大于或小于 50),并相应地有条件地呈现 HTML。

Python 脚本如下 −

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/hello/<int:score>')
def hello_name(score):
   return render_template('hello.html', marks = score)

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

hello.html 的 HTML 模板脚本如下 −

<!doctype html>
<html>
   <body>
      {% if marks>50 %}
         <h1> Your result is pass!</h1>
      {% else %}
         <h1>Your result is fail</h1>
      {% endif %}
   </body>
</html>

请注意,条件语句 if-elseendif 用分隔符 {%..%} 括起来。

运行 Python 脚本并访问 URL http://localhost/hello/60 ,然后访问 http://localhost/hello/30 ,以查看 HTML 按条件更改的输出。

Python 循环构造也可以在模板内部使用。在以下脚本中,当在浏览器中打开 URL http://localhost:5000/result 时,函数 result() 将一个字典对象发送到模板 results.html

result.html 的模板部分使用 for loop ,以将字典对象 result{} 的键值对作为 HTML 表格的单元格来呈现。

从 Python Shell 中运行以下代码。

from flask import Flask, render_template
app = Flask(__name__)

@app.route('/result')
def result():
   dict = {'phy':50,'che':60,'maths':70}
   return render_template('result.html', result = dict)

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

将以下 HTML 脚本保存为 result.html ,放在模板文件夹中。

<!doctype html>
<html>
   <body>
      <table border = 1>
         {% for key, value in result.items() %}
            <tr>
               <th> {{ key }} </th>
               <td> {{ value }} </td>
            </tr>
         {% endfor %}
      </table>
   </body>
</html>

此处,对应于 For 循环的 Python 语句同样用 {%..%} 括起来,而表达式 key and value 则放在 {{ }} 中。

开发开始运行后,在浏览器中打开 http://localhost:5000/result ,以获取以下输出。

table template example

Flask – Static Files

Web 应用程序通常需要一个静态文件,如 javascript 文件或 CSS 文件支持 Web 页面的显示。通常,Web 服务器被配置为为您提供它们,但在开发期间,这些文件是从包中的静态文件夹或模块旁边提供,并且可以在应用程序的 /static 上使用。

一个特殊的端点“static”用于生成静态文件的 URL。

在以下示例中,在 hello.js 中定义的 javascript 函数在 index.html 中的 HTML 按钮的 OnClick 事件上调用,该按钮在 ‘/’ Flask 应用程序的 URL 上呈现。

from flask import Flask, render_template
app = Flask(__name__)

@app.route("/")
def index():
   return render_template("index.html")

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

index.html 的 HTML 脚本如下所示。

<html>
   <head>
      <script type = "text/javascript"
         src = "{{ url_for('static', filename = 'hello.js') }}" ></script>
   </head>

   <body>
      <input type = "button" onclick = "sayHello()" value = "Say Hello" />
   </body>
</html>

hello.js 包含 sayHello() 函数。

function sayHello() {
   alert("Hello World")
}

Flask – Request Object

客户网页中的数据以全局请求对象的形式发送到服务器。为了处理请求数据,应从 Flask 模块导入它。

请求对象的重要属性如下列出:

  1. Form − 它是一个包含表单参数及其值的键值对的字典对象。

  2. args − 查询字符串的已解析内容,该查询字符串是问号 (?) 后的 URL 的一部分。

  3. Cookies − 存储 Cookie 名称和值的字典对象。

  4. files − 与上传文件相关的数据。

  5. method − 当前请求方法。

Flask – Sending Form Data to Template

我们已经看到,可以在 URL 规则中指定 http 方法。触发函数收到的 Form 数据可以以字典对象的形式收集,并将其转发到模板以便在相应的网页上渲染它。

在下面的示例中, ‘/’ URL 渲染一个包含表单的网页 (student.html)。填写其中的数据将发布到 ‘/result’ URL,该 URL 会触发 result() 函数。

results() 函数会以字典对象收集 request.form 中存在的表单数据,然后将其发送给 result.html 进行渲染。

模板会动态渲染 form 数据的 HTML 表格。

以下是应用程序的 Python 代码:

from flask import Flask, render_template, request
app = Flask(__name__)

@app.route('/')
def student():
   return render_template('student.html')

@app.route('/result',methods = ['POST', 'GET'])
def result():
   if request.method == 'POST':
      result = request.form
      return render_template("result.html",result = result)

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

以下是 student.html 的 HTML 脚本:

<html>
   <body>
      <form action = "http://localhost:5000/result" method = "POST">
         <p>Name <input type = "text" name = "Name" /></p>
         <p>Physics <input type = "text" name = "Physics" /></p>
         <p>Chemistry <input type = "text" name = "chemistry" /></p>
         <p>Maths <input type ="text" name = "Mathematics" /></p>
         <p><input type = "submit" value = "submit" /></p>
      </form>
   </body>
</html>

以下是模板 (result.html) 的代码:

<!doctype html>
<html>
   <body>
      <table border = 1>
         {% for key, value in result.items() %}
            <tr>
               <th> {{ key }} </th>
               <td> {{ value }} </td>
            </tr>
         {% endfor %}
      </table>
   </body>
</html>

运行 Python 脚本,并在浏览器中输入 URL http://localhost:5000/

submit marks

当点击 Submit 按钮时,表单数据以 HTML 表格形式呈现在 result.html 上。

marks table

Flask – Cookies

Cookie 以文本文件形式存储在客户端计算机上。其目的是记住并跟踪与客户端使用相关的数据,以便提供更好的访问者体验和网站统计信息。

一个 Request object 包含 Cookie 的属性。它是一个包含所有 Cookie 变量及其对应值的对象字典,这些变量及其对应值是由客户端传输的。此外,Cookie 还存储了它的过期时间、路径和网站的域名。

在 Flask 中,Cookie 设置在响应对象上。使用 make_response() 函数从视图函数的返回值中获取响应对象。然后,使用响应对象的 set_cookie() 函数存储一个 Cookie。

读回 Cookie 非常容易。 get() 属性的 request.cookies 方法用于读取 Cookie。

在下面的 Flask 应用中,当您访问 ‘/’ URL 时,会弹出一个简单的表单。

@app.route('/')
def index():
   return render_template('index.html')

此 HTML 页面包含一个文本输入。

<html>
   <body>
      <form action = "/setcookie" method = "POST">
         <p><h3>Enter userID</h3></p>
         <p><input type = 'text' name = 'nm'/></p>
         <p><input type = 'submit' value = 'Login'/></p>
      </form>
   </body>
</html>

该表单被提交到 ‘/setcookie’ URL。关联的视图函数设置一个 Cookie 名字 userID 并呈示另一个页面。

@app.route('/setcookie', methods = ['POST', 'GET'])
def setcookie():
   if request.method == 'POST':
   user = request.form['nm']

   resp = make_response(render_template('readcookie.html'))
   resp.set_cookie('userID', user)

   return resp

‘readcookie.html’ 包含一个到另一个视图函数 getcookie() 的超链接,后者读取并显示浏览器中的 Cookie 值。

@app.route('/getcookie')
def getcookie():
   name = request.cookies.get('userID')
   return '<h1>welcome '+name+'</h1>'

运行应用并访问 http://localhost:5000/

readcookie html

设置一个 Cookie 的结果以这种方式显示 −

result of setting cookie

读取回 Cookie 的输出显示如下。

reading cookie back

Flask – Sessions

类似于 Cookie,会话数据存储在客户端。会话是指客户端登录到一个服务器并登出时的时段。在这段时间内需要保存的数据都存储在客户端浏览器中。

每个客户端的会话都会被分配一个 Session ID 。会话数据被存储在 Cookie 之上,并且服务器对其进行加密签名。对于这种加密,Flask 应用需要一个定义过的 SECRET_KEY

会话对象也是一个包含会话变量及其关联值的关键值对的对象字典。

例如,要设置一个 ‘username’ 会话变量,请使用这条语句 −

Session[‘username’] = ’admin’

要释放一个会话变量,请使用 pop() 方法。

session.pop('username', None)

以下代码简单演示了会话在 Flask 中的工作。URL ‘/’ 仅仅提示用户登录,因为会话变量 ‘username’ 没有被设置。

@app.route('/')
def index():
   if 'username' in session:
      username = session['username']
         return 'Logged in as ' + username + '<br>' + \
         "<b><a href = '/logout'>click here to log out</a></b>"
   return "You are not logged in <br><a href = '/login'></b>" + \
      "click here to log in</b></a>"

当用户浏览到登录(login())视图函数的 ‘/login’ 时,因为它通过 GET 方法被调用,它会弹出一个登录表单。

一个表单被提交回 ‘/login’ ,现在会话变量被设置。应用被重定向到 ‘/’ 。这一次找到了会话变量 ‘username’

@app.route('/login', methods = ['GET', 'POST'])
def login():
   if request.method == 'POST':
      session['username'] = request.form['username']
      return redirect(url_for('index'))
   return '''

   <form action = "" method = "post">
      <p><input type = text name = username/></p>
      <p<<input type = submit value = Login/></p>
   </form>

   '''

应用程序还包含一个 logout() 视图函数,它弹出一个 ‘username’ 会话变量。因此, ‘/’ URL 再次显示打开页面。

@app.route('/logout')
def logout():
   # remove the username from the session if it is there
   session.pop('username', None)
   return redirect(url_for('index'))

运行应用程序并访问主页。(确保设置应用程序的 secret_key

from flask import Flask, session, redirect, url_for, escape, request
app = Flask(__name__)
app.secret_key = 'any random string’

输出如下所示。单击链接 “click here to log in”

login page using session

链接将被定向到另一个屏幕。输入 ‘admin’。

another login screen

屏幕会显示给你一条消息, ‘Logged in as admin’

logged in as admin

Flask – Redirect & Errors

Flask 类有一个 redirect() 函数。当被调用时,它返回一个响应对象,并且使用指定的HTTP状态码将用户重定向到另一个目标位置。

redirect() 函数的原型如下 −

Flask.redirect(location, statuscode, response)

在上面的函数中 −

  1. location 参数是响应应重定向到的 URL。

  2. statuscode 发送到浏览器的标头,默认为 302。

  3. response 参数用于实例化响应。

以下状态代码是标准化的 −

  1. HTTP_300_MULTIPLE_CHOICES

  2. HTTP_301_MOVED_PERMANENTLY

  3. HTTP_302_FOUND

  4. HTTP_303_SEE_OTHER

  5. HTTP_304_NOT_MODIFIED

  6. HTTP_305_USE_PROXY

  7. HTTP_306_RESERVED

  8. HTTP_307_TEMPORARY_REDIRECT

default status 代码是 302 ,用于 ‘found’

在以下示例中, redirect() 函数用于在登录尝试失败时再次显示登录页面。

from flask import Flask, redirect, url_for, render_template, request
# Initialize the Flask application
app = Flask(__name__)

@app.route('/')
def index():
   return render_template('log_in.html')

@app.route('/login',methods = ['POST', 'GET'])
def login():
   if request.method == 'POST' and request.form['username'] == 'admin' :
      return redirect(url_for('success'))
   else:
      return redirect(url_for('index'))

@app.route('/success')
def success():
   return 'logged in successfully'

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

Flask 类具有带错误代码的 abort() 函数。

Flask.abort(code)

Code 参数采用以下值之一 −

  1. 400 − 针对 Bad Request 请求

  2. 401 − for Unauthenticated

  3. 403 − for Forbidden

  4. 404 − 针对 Not Found 请求

  5. 406 − 针对 Not Acceptable 请求

  6. 415 − 不受支持的媒体类型

  7. 429 − 过多请求

让我们在上述代码中的 login() 函数中做一些小的更改。如果要显示 ‘Unauthourized’ 页面,请用调用 abort(401) 替换重新显示登录页面。

from flask import Flask, redirect, url_for, render_template, request, abort
app = Flask(__name__)

@app.route('/')
def index():
   return render_template('log_in.html')

@app.route('/login',methods = ['POST', 'GET'])
def login():
   if request.method == 'POST':
      if request.form['username'] == 'admin' :
         return redirect(url_for('success'))
      else:
         abort(401)
   else:
      return redirect(url_for('index'))

@app.route('/success')
def success():
   return 'logged in successfully'

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

Flask – Message Flashing

一个好的基于 GUI 的应用程序会向用户提供有关交互的反馈。例如,桌面应用程序会使用对话框或消息框,而 JavaScript 会使用警报以实现类似目的。

在 Flask Web 应用程序中,生成此类信息消息十分容易。Flask 框架的 Flashing 系统能够在一个视图中创建消息,并在名为 next 的视图函数中渲染它。

Flask 模块包含 flash() 方法。它将消息传递给下一个请求(通常是一个模板)。

flash(message, category)

在此,

  1. message 参数是实际的消息,用于显示。

  2. category 参数是可选的。它可以是“error”(错误)、“info”(信息)或“warning”(警告)。

为了从会话中删除消息,模板会调用 get_flashed_messages()

get_flashed_messages(with_categories, category_filter)

这两个参数都是可选的。第一个参数是元组,如果接收到消息,则说明类型。第二个参数对仅显示特定消息很有用。

以下闪光灯收到了模板中的消息。

{% with messages = get_flashed_messages() %}
   {% if messages %}
      {% for message in messages %}
         {{ message }}
      {% endfor %}
   {% endif %}
{% endwith %}

我们现在来看一个简单的例子,演示 Flask 中闪烁机制的操作。在下面的代码中,一个 ‘/’ URL 显示指向登录页面的链接,没有要显示的消息。

@app.route('/')
def index():
   return render_template('index.html')

这个链接将引导用户到 ‘/login’ URL,后者显示登录表单。提交后, login() 视图函数会验证用户名和密码,然后相应地闪烁 ‘success’ 消息或创建 ‘error’ 变量。

@app.route('/login', methods = ['GET', 'POST'])
def login():
   error = None

   if request.method == 'POST':
      if request.form['username'] != 'admin' or \
         request.form['password'] != 'admin':
         error = 'Invalid username or password. Please try again!'
      else:
         flash('You were successfully logged in')
         return redirect(url_for('index'))
   return render_template('login.html', error = error)

error 的情况下,重新显示登录模板并附有错误消息。

Login.html

<!doctype html>
<html>
   <body>
      <h1>Login</h1>

      {% if error %}
         <p><strong>Error:</strong> {{ error }}
      {% endif %}

      <form action = "" method = post>
         <dl>
            <dt>Username:</dt>
            <dd>
               <input type = text name = username
                  value = "{{request.form.username }}">
            </dd>
            <dt>Password:</dt>
            <dd><input type = password name = password></dd>
         </dl>
         <p><input type = submit value = Login></p>
      </form>
   </body>
</html>

另一方面,如果 login 成功,将在索引模板上闪烁一条成功消息。

Index.html

<!doctype html>
<html>
   <head>
      <title>Flask Message flashing</title>
   </head>
   <body>
      {% with messages = get_flashed_messages() %}
         {% if messages %}
            <ul>
               {% for message in messages %}
               <li<{{ message }}</li>
               {% endfor %}
            </ul>
         {% endif %}
      {% endwith %}

      <h1>Flask Message Flashing Example</h1>
      <p>Do you want to <a href = "{{ url_for('login') }}">
         <b>log in?</b></a></p>
   </body>
</html>

完整的 Flask 消息闪烁示例代码如下 −

Flash.py

from flask import Flask, flash, redirect, render_template, request, url_for
app = Flask(__name__)
app.secret_key = 'random string'

@app.route('/')
def index():
   return render_template('index.html')

@app.route('/login', methods = ['GET', 'POST'])
def login():
   error = None

   if request.method == 'POST':
      if request.form['username'] != 'admin' or \
         request.form['password'] != 'admin':
         error = 'Invalid username or password. Please try again!'
      else:
         flash('You were successfully logged in')
         return redirect(url_for('index'))

   return render_template('login.html', error = error)

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

在执行上述代码后,您将看到如下所示的屏幕。

flask message flashing example

当您单击该链接时,您将被定向到登录页面。

输入用户名和密码。

login page

单击 Login 。一条消息“您已成功登录”将被显示。

successfully logged in page

Flask – File Uploading

在 Flask 中处理文件上传非常容易。它需要一个将 enctype 属性设置为“multipart/form-data”的 HTML 表单,将文件发布到 URL。URL 处理程序从 request.files[] 对象获取文件并将其保存到所需位置。

每个上传的文件首先保存在服务器上的临时位置,然后才实际保存到其最终位置。目标文件的文件名可以硬编码,也可以从 request.files[file] 对象的 filename 属性获取。但是,建议使用 secure_filename() 函数获取其安全版本。

可以在 Flask 对象的配置设置中定义默认上传文件夹的路径和上传文件的大小。

app.config[‘UPLOAD_FOLDER’]

定义上传文件夹的路径

app.config[‘MAX_CONTENT_PATH’]

指定上传文件(以字节为单位)的最大大小

以下代码具有 ‘/upload’ URL 规则,用于显示模板文件夹中的 ‘upload.html’ ,以及 ‘/upload-file’ URL 规则,用于调用 uploader() 函数处理上传过程。

‘upload.html’ 有一个文件选择器按钮和一个提交按钮。

<html>
   <body>
      <form action = "http://localhost:5000/uploader" method = "POST"
         enctype = "multipart/form-data">
         <input type = "file" name = "file" />
         <input type = "submit"/>
      </form>
   </body>
</html>

您将看到如下所示的屏幕。

flask file uploading

选择文件后单击 Submit 。表单的 post 方法调用 ‘/upload_file’ URL。基础函数 uploader() 执行保存操作。

下面是 Flask 应用程序的 Python 代码。

from flask import Flask, render_template, request
from werkzeug import secure_filename
app = Flask(__name__)

@app.route('/upload')
def upload_file():
   return render_template('upload.html')

@app.route('/uploader', methods = ['GET', 'POST'])
def upload_file():
   if request.method == 'POST':
      f = request.files['file']
      f.save(secure_filename(f.filename))
      return 'file uploaded successfully'

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

Flask – Extensions

Flask 通常被称为微框架,因为它包括的核心的功能是基于 Werkzeug 的 WSGI 和路由,以及基于 Jinja2 的模板引擎。此外,Flask 框架支持 cookie 和会话,以及像 JSON 这样的 Web 帮助器、静态文件等。显然,这不足以开发一个功能齐全的 Web 应用程序。这意味着 Flask 扩展出现在了眼前。Flask 扩展为 Flask 框架提供可扩展性。

大量的 Flask 扩展可用。Flask 扩展是一个 Python 模块,它为 Flask 应用程序添加了特定类型支持。Flask 扩展注册表是一个可用的扩展目录。必需的扩展可以通过 pip 实用程序下载。

在本教程中,我们将讨论以下重要的 Flask 扩展 −

  1. Flask Mail − 为 Flask 应用程序提供 SMTP 接口

  2. Flask WTF − 添加 WTForms 的呈现和验证

  3. Flask SQLAlchemy − 为 Flask 应用程序添加 SQLAlchemy 支持

  4. Flask Sijax − Sijax 的接口 - Python/jQuery 库,使用户可以在 web 应用程序中轻松地使用 AJAX

每种类型的扩展通常会提供关于其使用情况的详尽文档。由于扩展是一个 Python 模块,所以需要导入它才能使用它。Flask 扩展通常被命名为 flask-foo。要导入,

from flask_foo import [class, function]

对于 Flask 0.7 之后的版本,您也可以使用语法 −

from flask.ext import foo

对于此用法,需要激活一个兼容性模块。可以通过运行 flaskext_compat.py 来安装它

import flaskext_compat
flaskext_compat.activate()
from flask.ext import foo

Flask – Mail

一个基于网络的应用程序常常需要一个向用户/客户端发送邮件的功能。 Flask-Mail 扩展使得使用任何电子邮件服务器设置一个简单的接口变得非常容易。

首先,应该使用 pip 实用程序安装 Flask-Mail 扩展。

pip install Flask-Mail

然后,需要通过设置以下应用程序参数的值来配置 Flask-Mail。

Sr.No

Parameters & Description

1

MAIL_SERVER 电子邮件服务器的名称/IP 地址

2

MAIL_PORT 使用的服务器的端口号

3

MAIL_USE_TLS 启用/禁用传输层安全加密

4

MAIL_USE_SSL 启用/禁用安全套接字层加密

5

MAIL_DEBUG 调试支持。默认为 Flask 应用程序的调试状态

6

MAIL_USERNAME User name of sender

7

MAIL_PASSWORD password of sender

8

MAIL_DEFAULT_SENDER sets default sender

9

MAIL_MAX_EMAILS 设置要发送的最大邮件数

10

MAIL_SUPPRESS_SEND 如果 app.testing 设置为真,则发送被禁止

11

MAIL_ASCII_ATTACHMENTS 如果设置为真,则将附件的文件名转换为 ASCII

flask-mail 模块包含以下重要类的定义。

Mail class

它管理电子邮件消息传递的需求。该类的构造器采用以下形式 −

flask-mail.Mail(app = None)

构造器以 Flask 应用程序对象作为参数。

Methods of Mail class

Sr.No

Methods & Description

1

send() 发送 Message 类的对象的内容

2

connect() 打开与邮件主机的连接

3

send_message() Sends message object

Message class

它封装了一封电子邮件。Message 类的构造器有几个参数 −

flask-mail.Message(subject, recipients, body, html, sender, cc, bcc,
   reply-to, date, charset, extra_headers, mail_options, rcpt_options)

Message class methods

attach() − 向邮件添加附件。此方法采用以下参数 −

  1. filename − 附件文件的文件名

  2. content_type − 文件的 MIME 类型

  3. data − 原始文件数据

  4. disposition − 以及内容处置(如存在)

add_recipient() − 向电子邮件添加另一位收件人

在以下示例中,将 Google Gmail 服务的 SMTP 服务器用作 Flask-Mail 配置的 MAIL_SERVER。

Step 1 − 在代码中从 flask-mail 模块导入 Mail 和 Message 类。

from flask_mail import Mail, Message

Step 2 − 然后根据以下设置配置 Flask-Mail。

app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True

Step 3 − 创建 Mail 类的一个实例。

mail = Mail(app)

Step 4 − 在由 URL 规则 (‘/’) 映射的 Python 函数中设置一个 Message 对象。

@app.route("/")
def index():
   msg = Message('Hello', sender = 'yourId@gmail.com', recipients = ['id1@gmail.com'])
   msg.body = "This is the email body"
   mail.send(msg)
   return "Sent"

Step 5 − 整个代码如下。在 Python Shell 中运行以下脚本并访问 http://localhost:5000/.

from flask import Flask
from flask_mail import Mail, Message

app =Flask(__name__)
mail=Mail(app)

app.config['MAIL_SERVER']='smtp.gmail.com'
app.config['MAIL_PORT'] = 465
app.config['MAIL_USERNAME'] = 'yourId@gmail.com'
app.config['MAIL_PASSWORD'] = '*****'
app.config['MAIL_USE_TLS'] = False
app.config['MAIL_USE_SSL'] = True
mail = Mail(app)

@app.route("/")
def index():
   msg = Message('Hello', sender = 'yourId@gmail.com', recipients = ['id1@gmail.com'])
   msg.body = "Hello Flask message sent from Flask-Mail"
   mail.send(msg)
   return "Sent"

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

请注意,Gmail 服务中的内置安全功能可能会阻止此登录尝试。您可能需要降低安全级别。请登录您的 Gmail 帐户并访问 this 链接以降低安全性。

decrease the security

Flask – WTF

Web 应用程序的基本方面之一是为用户提供用户界面。HTML 提供了一个 <form> 标记,用于设计界面。可以适当使用文本输入、单选按钮、选择等 Form’s 元素。

用户输入的数据通过 GET 或 POST 方法以 Http 请求消息的形式提交到服务器端脚本。

  1. 服务器端脚本必须从 http 请求数据中重新创建表单元素。因此实际上,表单元素必须定义两次——一次在 HTML 中,一次在服务器端脚本中。

  2. 使用 HTML 表单的另一个缺点是,很难(如果不是不可能的话)动态呈现表单元素。HTML 本身没有提供验证用户输入的方法。

这时 WTForms 派上用场,它是一个灵活的表单呈现和验证库。Flask-WTF 扩展提供了一个与 WTForms 库简单的界面。

使用 Flask-WTF ,我们可以在 Python 脚本中定义表单字段,并使用 HTML 模板呈现它们。还可以对 WTF 字段应用验证。

让我们看看此 HTML 的动态生成是如何运作的。

首先,需要安装 Flask-WTF 扩展。

pip install flask-WTF

安装的包包含一个 Form 类,必须将其用作用户定义表单的父元素。

WTforms 包含各种表单字段的定义。一些 Standard form fields 如下。

Sr.No

标准表单字段和说明

1

TextField 表示 <input type = 'text'>HTML 表单元素

2

BooleanField 表示 <input type = 'checkbox'> HTML 表单元素

3

带有小数点的数字显示文本字段

4

IntegerField TextField for displaying integer

5

RadioField 表示 <input type = 'radio'> HTML 表单元素

6

SelectField Represents select form element

7

TextAreaField 表示<textarea>html 表单元素

8

PasswordField 表示 <input type = 'password'> HTML 表单元素

9

SubmitField 表示 <input type = 'submit'> 表单元素

例如,一个包含文本字段的表单可以设计如下 −

from flask_wtf import Form
from wtforms import TextField

class ContactForm(Form):
   name = TextField("Name Of Student")

除了 ‘name’ 字段,还自动创建 CSRF 令牌的隐藏字段。这是为了防止 Cross Site Request Forgery 攻击。

渲染时,这将生成如下所示的等效 HTML 脚本。

<input id = "csrf_token" name = "csrf_token" type = "hidden" />
<label for = "name">Name Of Student</label><br>
<input id = "name" name = "name" type = "text" value = "" />

Flask 应用程序中使用了用户定义的表单类,并且表单使用模板渲染。

from flask import Flask, render_template
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'development key'

@app.route('/contact')
def contact():
   form = ContactForm()
   return render_template('contact.html', form = form)

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

WTForms 包还包含验证器类。它可用于对表单字段应用验证。以下列表显示了常用的验证器。

Sr.No

Validators Class & Description

1

DataRequired 检查输入字段是否为空

2

Email 检查字段中的文本是否遵循电子邮件 ID 惯例

3

IPAddress 验证输入字段中的IP地址

4

Length 验证输入字段中的字符串长度是否在给定范围内

5

NumberRange 验证输入字段中的数字是否在给定范围内

6

URL 验证输入字段中输入的URL

现在,我们将在联系表单的 name 字段中应用 ‘DataRequired’ 验证规则。

name = TextField("Name Of Student",[validators.Required("Please enter your name.")])

表单对象的 validate() 函数验证表单数据,如果验证失败则抛出验证错误。将 Error 消息发送到模板。在HTML模板中,错误消息会动态呈现。

{% for message in form.name.errors %}
   {{ message }}
{% endfor %}

以下示例 демонстрирует介绍的概念。 Contact form 的设计如下 (forms.py) 所示。

from flask_wtf import Form
from wtforms import TextField, IntegerField, TextAreaField, SubmitField, RadioField,
   SelectField

from wtforms import validators, ValidationError

class ContactForm(Form):
   name = TextField("Name Of Student",[validators.Required("Please enter
      your name.")])
   Gender = RadioField('Gender', choices = [('M','Male'),('F','Female')])
   Address = TextAreaField("Address")

   email = TextField("Email",[validators.Required("Please enter your email address."),
      validators.Email("Please enter your email address.")])

   Age = IntegerField("age")
   language = SelectField('Languages', choices = [('cpp', 'C++'),
      ('py', 'Python')])
   submit = SubmitField("Send")

验证器适用于 NameEmail 字段。

以下是Flask应用程序脚本 (formexample.py)

from flask import Flask, render_template, request, flash
from forms import ContactForm
app = Flask(__name__)
app.secret_key = 'development key'

@app.route('/contact', methods = ['GET', 'POST'])
def contact():
   form = ContactForm()

   if request.method == 'POST':
      if form.validate() == False:
         flash('All fields are required.')
         return render_template('contact.html', form = form)
      else:
         return render_template('success.html')
      elif request.method == 'GET':
         return render_template('contact.html', form = form)

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

模板的脚 (contact.html) 如下 −

<!doctype html>
<html>
   <body>
      <h2 style = "text-align: center;">Contact Form</h2>

      {% for message in form.name.errors %}
         <div>{{ message }}</div>
      {% endfor %}

      {% for message in form.email.errors %}
         <div>{{ message }}</div>
      {% endfor %}

      <form action = "http://localhost:5000/contact" method = post>
         <fieldset>
            <legend>Contact Form</legend>
            {{ form.hidden_tag() }}

            <div style = font-size:20px; font-weight:bold; margin-left:150px;>
               {{ form.name.label }}<br>
               {{ form.name }}
               <br>

               {{ form.Gender.label }} {{ form.Gender }}
               {{ form.Address.label }}<br>
               {{ form.Address }}
               <br>

               {{ form.email.label }}<br>
               {{ form.email }}
               <br>

               {{ form.Age.label }}<br>
               {{ form.Age }}
               <br>

               {{ form.language.label }}<br>
               {{ form.language }}
               <br>
               {{ form.submit }}
            </div>

         </fieldset>
      </form>
   </body>
</html>

在Python shell中运行 formexample.py 并访问URL http://localhost:5000/contactContact 表单将按如下所示显示。

form example

如果有任何错误,页面将如下所示 −

form error page

如果没有错误,将呈现 ‘success.html’

form success page

Flask – SQLite

Python对 SQlite 有内置支持。Python发行版附带了SQlite3模块。有关在Python中使用SQLite数据库的详细教程,请参阅 this link 。在本节中,我们将看到Flask应用程序如何与SQLite交互。

创建SQLite数据库 ‘database.db’ 并在其中创建一个学生的表。

import sqlite3

conn = sqlite3.connect('database.db')
print "Opened database successfully";

conn.execute('CREATE TABLE students (name TEXT, addr TEXT, city TEXT, pin TEXT)')
print "Table created successfully";
conn.close()

我们的Flask应用程序有三个 View 函数。

第一个 new_student() 函数绑定到URL规则 (‘/addnew’) 。它呈现一个包含学生信息表单的HTML文件。

@app.route('/enternew')
def new_student():
   return render_template('student.html')

‘student.html’ 的HTML脚本如下 −

<html>
   <body>
      <form action = "{{ url_for('addrec') }}" method = "POST">
         <h3>Student Information</h3>
         Name<br>
         <input type = "text" name = "nm" /></br>

         Address<br>
         <textarea name = "add" ></textarea><br>

         City<br>
         <input type = "text" name = "city" /><br>

         PINCODE<br>
         <input type = "text" name = "pin" /><br>
         <input type = "submit" value = "submit" /><br>
      </form>
   </body>
</html>

如您所见,表单数据发布到绑定 addrec() 函数的 ‘/addrec’ URL。

addrec() 函数通过 POST 方法检索表单数据并插入 students 表中。插入操作成功或失败的对应消息呈现在 ‘result.html’ 上。

@app.route('/addrec',methods = ['POST', 'GET'])
def addrec():
   if request.method == 'POST':
      try:
         nm = request.form['nm']
         addr = request.form['add']
         city = request.form['city']
         pin = request.form['pin']

         with sql.connect("database.db") as con:
            cur = con.cursor()
            cur.execute("INSERT INTO students (name,addr,city,pin)
               VALUES (?,?,?,?)",(nm,addr,city,pin) )

            con.commit()
            msg = "Record successfully added"
      except:
         con.rollback()
         msg = "error in insert operation"

      finally:
         return render_template("result.html",msg = msg)
         con.close()

result.html 的 HTML 脚本包含转义语句 {{msg}} ,它显示 Insert 操作的结果。

<!doctype html>
<html>
   <body>
      result of addition : {{ msg }}
      <h2><a href = "\">go back to home page</a></h2>
   </body>
</html>

该应用程序包含另一个由 ‘/list’ URL 表示的 list() 函数。它将 ‘rows’ 填充成一个 MultiDict 对象,其中包含 students 表中的所有记录。该对象传递给 list.html 模板。

@app.route('/list')
def list():
   con = sql.connect("database.db")
   con.row_factory = sql.Row

   cur = con.cursor()
   cur.execute("select * from students")

   rows = cur.fetchall();
   return render_template("list.html",rows = rows)

list.html 是一个模板,它对行集进行迭代并在 HTML 表中呈现数据。

<!doctype html>
<html>
   <body>
      <table border = 1>
         <thead>
            <td>Name</td>
            <td>Address>/td<
            <td>city</td>
            <td>Pincode</td>
         </thead>

         {% for row in rows %}
            <tr>
               <td>{{row["name"]}}</td>
               <td>{{row["addr"]}}</td>
               <td> {{ row["city"]}}</td>
               <td>{{row['pin']}}</td>
            </tr>
         {% endfor %}
      </table>

      <a href = "/">Go back to home page</a>
   </body>
</html>

最后, ‘/’ URL 规则呈现一个 ‘home.html’ ,作为应用程序的入口点。

@app.route('/')
def home():
   return render_template('home.html')

以下为 Flask-SQLite 应用程序的完整代码。

from flask import Flask, render_template, request
import sqlite3 as sql
app = Flask(__name__)

@app.route('/')
def home():
   return render_template('home.html')

@app.route('/enternew')
def new_student():
   return render_template('student.html')

@app.route('/addrec',methods = ['POST', 'GET'])
def addrec():
   if request.method == 'POST':
      try:
         nm = request.form['nm']
         addr = request.form['add']
         city = request.form['city']
         pin = request.form['pin']

         with sql.connect("database.db") as con:
            cur = con.cursor()

            cur.execute("INSERT INTO students (name,addr,city,pin)
               VALUES (?,?,?,?)",(nm,addr,city,pin) )

            con.commit()
            msg = "Record successfully added"
      except:
         con.rollback()
         msg = "error in insert operation"

      finally:
         return render_template("result.html",msg = msg)
         con.close()

@app.route('/list')
def list():
   con = sql.connect("database.db")
   con.row_factory = sql.Row

   cur = con.cursor()
   cur.execute("select * from students")

   rows = cur.fetchall();
   return render_template("list.html",rows = rows)

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

从 Python Shell 运行此脚本并作为开发服务器开始运行。在浏览器中访问 http://localhost:5000/ ,它会显示类似这样的简单菜单 -

simple menu

点击 ‘Add New Record’ 链接以打开 Student Information 表单。

adding new record

填写表单字段并提交。底层函数会将记录插入 students 表。

record successfully added

返回主页并点击 ‘Show List’ 链接。程序会显示包含示例数据的表格。

table showing sample data

Flask – SQLAlchemy

在 Flask Web 应用中使用原始 SQL 在数据库上执行 CRUD 操作可能会很繁琐。相反, SQLAlchemy ,一个 Python 工具包是一个强大的 OR Mapper ,它为应用程序开发人员提供了 SQL 的全部功能和灵活性。Flask-SQLAlchemy 是 Flask 扩展,它为 Flask 应用程序添加了对 SQLAlchemy 的支持。

使用原始 SQL 在数据库上执行 CRUD 操作可能会很繁琐。相反, SQLAlchemy ,一个 Python 工具包是一个强大的 OR Mapper ,它为应用程序开发人员提供了 SQL 的全部功能和灵活性。Flask-SQLAlchemy 是 Flask 扩展,它为 Flask 应用程序添加了对 SQLAlchemy 的支持。

大多数编程语言平台都是面向对象的。另一方面,RDBMS 服务器中的数据以表格的形式存储。对象关系映射是一种将对象参数映射到底层 RDBMS 表结构的技术。ORM API 提供了执行 CRUD 操作的方法,而无需编写原始 SQL 语句。

在本章中,我们将学习 Flask-SQLAlchemy 的 ORM 技术并构建一个小 Web 应用程序。

Step 1 − 安装 Flask-SQLAlchemy 扩展。

pip install flask-sqlalchemy

Step 2 − 您需要从该模块导入 SQLAlchemy 类。

from flask_sqlalchemy import SQLAlchemy

Step 3 − 现在创建一个 Flask 应用程序对象,并将 URI 设置为要使用的数据库。

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'

Step 4 − 然后创建一个 SQLAlchemy 类的对象,并将应用程序对象作为参数。该对象包含 ORM 操作的辅助函数。它还提供了一个父级 Model 类,用户定义的模型就是使用此类声明的。在下面的代码段中,创建了一个 students 模型。

db = SQLAlchemy(app)
class students(db.Model):
   id = db.Column('student_id', db.Integer, primary_key = True)
   name = db.Column(db.String(100))
   city = db.Column(db.String(50))
   addr = db.Column(db.String(200))
   pin = db.Column(db.String(10))

def __init__(self, name, city, addr,pin):
   self.name = name
   self.city = city
   self.addr = addr
   self.pin = pin

Step 5 − 要创建/使用 URI 中提到的数据库,请运行 create_all() 方法。

db.create_all()

Session 对象 SQLAlchemy 管理 ORM 对象的所有持久性操作。

以下会话方法执行 CRUD 操作 −

  1. db.session.add (model object) − 向映射表中插入记录

  2. db.session.delete (model object) − 从表中删除记录

  3. model.query.all() − 检索表中的所有记录(对应于 SELECT 查询)。

您可以使用过滤器属性将过滤器应用于检索的记录集。例如,为了检索学生表中具有 city = ’Hyderabad’ 的记录,请使用以下语句 −

Students.query.filter_by(city = ’Hyderabad’).all()

有了这么多的背景,现在我们应该为我们的应用程序提供视图函数,以便添加学生数据。

应用程序的入口点是 show_all() 函数,绑定到 ‘/’ URL。学生表的记录集作为参数发送到 HTML 模板。模板中的服务器端代码在 HTML 表格形式中呈现记录。

@app.route('/')
def show_all():
   return render_template('show_all.html', students = students.query.all() )

模板 (‘show_all.html’) 的 HTML 脚本如下 −

<!DOCTYPE html>
<html lang = "en">
   <head></head>
   <body>
      <h3>
         <a href = "{{ url_for('show_all') }}">Comments - Flask
            SQLAlchemy example</a>
      </h3>

      <hr/>
      {%- for message in get_flashed_messages() %}
         {{ message }}
      {%- endfor %}

      <h3>Students (<a href = "{{ url_for('new') }}">Add Student
         </a>)</h3>

      <table>
         <thead>
            <tr>
               <th>Name</th>
               <th>City</th>
               <th>Address</th>
               <th>Pin</th>
            </tr>
         </thead>

         <tbody>
            {% for student in students %}
               <tr>
                  <td>{{ student.name }}</td>
                  <td>{{ student.city }}</td>
                  <td>{{ student.addr }}</td>
                  <td>{{ student.pin }}</td>
               </tr>
            {% endfor %}
         </tbody>
      </table>
   </body>
</html>

上面页面包含一个超链接,指向 ‘/new’ URL 映射 new() 函数。单击后,它将打开“学生信息”表单。数据在 POST 方法中发布到同一 URL。

new.html

<!DOCTYPE html>
<html>
   <body>
      <h3>Students - Flask SQLAlchemy example</h3>
      <hr/>

      {%- for category, message in get_flashed_messages(with_categories = true) %}
         <div class = "alert alert-danger">
            {{ message }}
         </div>
      {%- endfor %}

      <form action = "{{ request.path }}" method = "post">
         <label for = "name">Name</label><br>
         <input type = "text" name = "name" placeholder = "Name" /><br>
         <label for = "email">City</label><br>
         <input type = "text" name = "city" placeholder = "city" /><br>
         <label for = "addr">addr</label><br>
         <textarea name = "addr" placeholder = "addr"></textarea><br>
         <label for = "PIN">City</label><br>
         <input type = "text" name = "pin" placeholder = "pin" /><br>
         <input type = "submit" value = "Submit" />
      </form>
   </body>
</html>

当 HTTP 方法被检测为 POST 时,表单数据被添加到学生表中,并且应用程序返回到主页,显示已添加的数据。

@app.route('/new', methods = ['GET', 'POST'])
def new():
   if request.method == 'POST':
      if not request.form['name'] or not request.form['city'] or not request.form['addr']:
         flash('Please enter all the fields', 'error')
      else:
         student = students(request.form['name'], request.form['city'],
            request.form['addr'], request.form['pin'])

         db.session.add(student)
         db.session.commit()

         flash('Record was successfully added')
         return redirect(url_for('show_all'))
   return render_template('new.html')

下面是应用程序的完整代码 (app.py)

from flask import Flask, request, flash, url_for, redirect, render_template
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'
app.config['SECRET_KEY'] = "random string"

db = SQLAlchemy(app)

class students(db.Model):
   id = db.Column('student_id', db.Integer, primary_key = True)
   name = db.Column(db.String(100))
   city = db.Column(db.String(50))
   addr = db.Column(db.String(200))
   pin = db.Column(db.String(10))

def __init__(self, name, city, addr,pin):
   self.name = name
   self.city = city
   self.addr = addr
   self.pin = pin

@app.route('/')
def show_all():
   return render_template('show_all.html', students = students.query.all() )

@app.route('/new', methods = ['GET', 'POST'])
def new():
   if request.method == 'POST':
      if not request.form['name'] or not request.form['city'] or not request.form['addr']:
         flash('Please enter all the fields', 'error')
      else:
         student = students(request.form['name'], request.form['city'],
            request.form['addr'], request.form['pin'])

         db.session.add(student)
         db.session.commit()
         flash('Record was successfully added')
         return redirect(url_for('show_all'))
   return render_template('new.html')

if __name__ == '__main__':
   db.create_all()
   app.run(debug = True)

从 Python shell 运行脚本,并在浏览器中输入 http://localhost:5000/

flask sqlalchemy example

单击 ‘Add Student’ 链接以打开 Student information 表单。

add student

填写并提交表单。主页将重新显示已提交的数据。

我们可以看到如下所示的输出。

flask sqlalchemy example output

Flask – Sijax

Sijax 代表 ‘Simple Ajax’ ,它是 Python/jQuery 库,旨在帮助您轻松地将 Ajax 引入到您的应用程序中。它使用 jQuery.ajax 发起 AJAX 请求。

Installation

安装 Flask-Sijax 非常简单。

pip install flask-sijax

Configuration

  1. SIJAX_STATIC_PATH − 您希望镜像 Sijax javascript 文件的静态路径。默认位置是 static/js/sijax 。在该文件夹中, sijax.jsjson2.js 文件会被保存。

  2. SIJAX_JSON_URI − 从此加载 json2.js 静态文件的 URI

Sijax 使用 JSON 在浏览器和服务器之间传递数据。这意味着浏览器要么需要原生支持 JSON ,要么通过 json2.js 文件获取 JSON 支持。

那样注册的函数无法提供 Sijax 功能,因为默认情况下无法通过 POST 方法访问它们(而 Sijax 使用 POST 请求)。

要使 View 函数能够处理 Sijax 请求,可通过 POST 使用 @app.route('/url', methods = ['GET', 'POST']) 访问它,或者像这样使用 @flask_sijax.route 帮助器装饰器 −

@flask_sijax.route(app, '/hello')

每个 Sijax 处理程序函数(如这个)都会至少自动接收一个参数,就像 Python 将“self”传递给对象方法一样。 ‘obj_response’ 参数是函数向浏览器返回响应的一种方式。

def say_hi(obj_response):
   obj_response.alert('Hi there!')

当检测到 Sijax 请求时,Sijax 会像这样处理它 −

g.sijax.register_callback('say_hi', say_hi)
   return g.sijax.process_request()

Sijax Application

一个最小的 Sijax 应用程序代码如下 −

import os
from flask import Flask, g
from flask_sijax import sijax

path = os.path.join('.', os.path.dirname(__file__), 'static/js/sijax/')
app = Flask(__name__)

app.config['SIJAX_STATIC_PATH'] = path
app.config['SIJAX_JSON_URI'] = '/static/js/sijax/json2.js'
flask_sijax.Sijax(app)

@app.route('/')
def index():
   return 'Index'

@flask_sijax.route(app, '/hello')
def hello():
   def say_hi(obj_response):
      obj_response.alert('Hi there!')
   if g.sijax.is_sijax_request:
      # Sijax request detected - let Sijax handle it
      g.sijax.register_callback('say_hi', say_hi)
      return g.sijax.process_request()
      return _render_template('sijaxexample.html')

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

当 Sijax 请求(一个特殊的 jQuery.ajax() 请求)发送到服务器时,这个请求会被服务器上的 g.sijax.is_sijax_request() 检测到,在这种情况下,您可以让 Sijax 处理该请求。

使用 g.sijax.register_callback() 注册的所有函数都公开以便从浏览器调用。

调用 g.sijax.process_request() 会指示 Sijax 执行适当的(先前注册的)函数并将响应返回至浏览器。

Flask – Deployment

Externally Visible Server

在开发服务器上只能在设置开发环境的计算机上访问 Flask 应用程序。这是一项默认行为,因为在调试模式下,用户可以在计算机上执行任意代码。

如果禁用 debug ,可以通过将主机名设置为 ‘0.0.0.0’ ,使本地计算机上的开发服务器可供网络上的用户使用。

app.run(host = ’0.0.0.0’)

因此,您的操作系统将侦听到所有公共 IP。

Deployment

要从开发环境切换到成熟的生产环境,应用程序需要部署在真正的 Web 服务器上。根据您的情况,可以使用不同的选项来部署 Flask Web 应用程序。

对于小型应用程序,您可以考虑将它部署在以下任何托管平台上,所有这些平台都为小型应用程序提供免费计划。

  1. Heroku

  2. dotcloud

  3. webfaction

Flask 应用程序可以在这些云平台上部署。此外,也可以在 Google 云平台上部署 Flask 应用程序。Localtunnel 服务允许您在本地主机上共享您的应用程序,而无需更改 DNS 和防火墙设置。

如果您倾向于使用专用 Web 服务器来替代上述共享平台,则可以使用以下选项进行探索。

mod_wsgi

mod_wsgi 是一个 Apache 模块,为在 Apache 服务器上托管基于 Python 的 Web 应用程序提供了一个符合 WSGI 的接口。

Installing mod_wsgi

要直接从 PyPi 安装官方版本,您可以运行 -

pip install mod_wsgi

要验证安装是否成功,请使用 start-server 命令运行 mod_wsgi-express 脚本 -

mod_wsgi-express start-server

这将在端口 8000 上启动 Apache/mod_wsgi。然后,您可以通过将浏览器的指针指向 -

http://localhost:8000/

Creating .wsgi file

应该有一个 yourapplication.wsgi 文件。此文件包含在启动时执行的代码 mod_wsgi, 以获取应用程序对象。对于大多数应用程序,以下文件应该足够 -

from yourapplication import app as application

确保 yourapplication 和正在使用的所有库都位于 Python 加载路径上。

Configuring Apache

您需要告诉 mod_wsgi, 您应用程序的位置。

<VirtualHost *>
   ServerName example.com
   WSGIScriptAlias / C:\yourdir\yourapp.wsgi

   <Directory C:\yourdir>
      Order deny,allow
      Allow from all
   </Directory>

</VirtualHost>

Standalone WSGI containers

Python 中编写了许多流行的服务器,这些服务器包含 WSGI 应用程序并提供 HTTP。

  1. Gunicorn

  2. Tornado

  3. Gevent

  4. Twisted Web

Flask – FastCGI

FastCGI 是适用于 nginix、lighttpd 和 Cherokee 等网络服务器的 Flask 应用程序的另一个部署选项。

Configuring FastCGI

首先,您需要创建 FastCGI 服务器文件。让我们称之为 yourapplication.fcgi

from flup.server.fcgi import WSGIServer
from yourapplication import app

if __name__ == '__main__':
   WSGIServer(app).run()

nginx 和更早版本的 lighttpd 需要一个套接字来明确地传递与 FastCGI 服务器进行通信。要做到这一点,您需要将套接字的路径传递给 WSGIServer

WSGIServer(application, bindAddress = '/path/to/fcgi.sock').run()

Configuring Apache

对于基本的 Apache 部署,您的 .fcgi 文件将出现在您的应用程序 URL 中,例如 example.com/yourapplication.fcgi/hello/ 。有几种方法可以配置您的应用程序,以便 yourapplication.fcgi 不出现在 URL 中。

<VirtualHost *>
   ServerName example.com
   ScriptAlias / /path/to/yourapplication.fcgi/
</VirtualHost>

Configuring lighttpd

lighttpd 的基本配置如下所示 -

fastcgi.server = ("/yourapplication.fcgi" => ((
   "socket" => "/tmp/yourapplication-fcgi.sock",
   "bin-path" => "/var/www/yourapplication/yourapplication.fcgi",
   "check-local" => "disable",
   "max-procs" => 1
)))

alias.url = (
   "/static/" => "/path/to/your/static"
)

url.rewrite-once = (
   "^(/static($|/.*))$" => "$1",
   "^(/.*)$" => "/yourapplication.fcgi$1"
)

请记住启用 FastCGI ,别名和重写模块。此配置将应用程序绑定到 /yourapplication