- Flask 教程
- Flask - 首页
- Flask - 概述
- Flask - 环境配置
- Flask - 应用程序
- Flask - 路由
- Flask - 变量规则
- Flask - URL构建
- Flask - HTTP 方法
- Flask - 模板
- Flask - 静态文件
- Flask - 请求对象
- 将表单数据发送到模板
- Flask - Cookie
- Flask - Session
- Flask - 重定向和错误处理
- Flask - 消息闪现
- Flask - 文件上传
- Flask - 扩展
- Flask - 邮件发送
- Flask - WTF
- Flask - SQLite
- Flask - SQLAlchemy
- Flask - Sijax
- Flask - 部署
- Flask - FastCGI
- Flask 有用资源
- Flask 快速指南
- Flask - 有用资源
- Flask - 讨论
Flask 快速指南
Flask – 概述
什么是Web框架?
Web应用程序框架,简称Web框架,代表着一组库和模块,使Web应用程序开发人员能够编写应用程序,而无需处理低级细节,例如协议、线程管理等。
什么是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模板系统将模板与某个数据源结合起来,以呈现动态网页。
Flask通常被称为微框架。它旨在保持应用程序的核心简单但可扩展。Flask没有内置的数据库处理抽象层,也没有表单验证支持。相反,Flask支持扩展以向应用程序添加此类功能。本教程后面将讨论一些流行的Flask扩展。
Flask – 环境配置
先决条件
安装Flask通常需要Python 2.6或更高版本。虽然Flask及其依赖项可以与Python 3(Python 3.3及更高版本)很好地配合使用,但许多Flask扩展并不完全支持它。因此,建议在Python 2.7上安装Flask。
安装virtualenv用于开发环境
virtualenv是一个虚拟Python环境构建器。它帮助用户并排创建多个Python环境。因此,它可以避免不同版本的库之间的兼容性问题。
以下命令安装virtualenv
pip install virtualenv
此命令需要管理员权限。在Linux/Mac OS上,在pip之前添加sudo。如果您使用的是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 – 应用程序
为了测试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构造函数将当前模块(__name__)的名称作为参数。
Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用关联的函数。
app.route(rule, options)
rule参数表示URL与函数的绑定。
options是转发到底层Rule对象的参数列表。
在上面的示例中,‘/’ URL绑定到hello_world()函数。因此,当在浏览器中打开Web服务器的主页时,将呈现此函数的输出。
最后,Flask类的run()方法在本地开发服务器上运行应用程序。
app.run(host, port, debug, options)
所有参数都是可选的
序号 | 参数和描述 |
---|---|
1 |
host 要监听的主机名。默认为127.0.0.1(localhost)。设置为‘0.0.0.0’以使服务器可从外部访问 |
2 |
port 默认为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’消息。
调试模式
通过调用run()方法启动Flask应用程序。但是,在应用程序开发过程中,应该为代码中的每次更改手动重新启动它。为了避免这种不便,启用调试支持。如果代码发生更改,服务器将重新加载自身。如果应用程序中存在任何错误,它还将提供一个有用的调试器来跟踪这些错误。
通过在运行前将application对象的debug属性设置为True或将debug参数传递给run()方法来启用Debug模式。
app.debug = True app.run() app.run(debug = True)
Flask – 路由
现代Web框架使用路由技术来帮助用户记住应用程序URL。它有助于直接访问所需页面,而无需从主页导航。
Flask中的route()装饰器用于将URL绑定到函数。例如:
@app.route(‘/hello’) def hello_world(): return ‘hello world’
这里,URL‘/hello’规则绑定到hello_world()函数。因此,如果用户访问https://127.0.0.1:5000/hello URL,则hello_world()函数的输出将在浏览器中呈现。
应用程序对象的add_url_rule()函数也可用于将URL与函数绑定,如上例所示,使用了route()。
装饰器的目的也由以下表示法提供:
def hello_world(): return ‘hello world’ app.add_url_rule(‘/’, ‘hello’, hello_world)
Flask – 变量规则
可以通过向rule参数添加可变部分来动态构建URL。此可变部分标记为<variable-name>。它作为关键字参数传递给与该规则关联的函数。
在下面的示例中,route()装饰器的rule参数包含附加到URL‘/hello’的可变部分<name>。因此,如果在浏览器中输入https://127.0.0.1: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运行它。接下来,打开浏览器并输入URLhttps://127.0.0.1:5000/hello/TutorialsPoint。
浏览器将显示以下输出:
Hello TutorialsPoint!
除了默认的字符串变量部分外,还可以使用以下转换器构建规则:
序号 | 转换器和描述 |
---|---|
1 |
int 接受整数 |
2 |
float 用于浮点值 |
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运行上述代码。在浏览器中访问URLhttps://127.0.0.1:5000/blog/11。
给定的数字用作show_blog()函数的参数。浏览器显示以下输出:
Blog Number 11
在浏览器中输入此URL:https://127.0.0.1:5000/rev/1.1
revision()函数将浮点数作为参数。以下结果出现在浏览器窗口中:
Revision Number 1.100000
Flask的URL规则基于Werkzeug的路由模块。这确保了生成的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构建
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为:https://127.0.0.1:5000/user/admin
浏览器中的应用程序响应为:
Hello Admin
在浏览器中输入以下URL:https://127.0.0.1:5000/user/mvl
应用程序响应现在更改为:
Hello mvl as Guest
Flask – HTTP 方法
Http协议是万维网中数据通信的基础。此协议中定义了从指定URL检索数据的不同方法。
下表总结了不同的http方法:
序号 | 方法和描述 |
---|---|
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 = "https://127.0.0.1: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,在文本字段中输入名称,然后单击Submit。
表单数据POST到表单标记的action子句中的URL。
https://127.0.0.1/login映射到login()函数。由于服务器已通过POST方法接收到数据,因此从表单数据中获得的‘nm’参数的值通过以下方式获得:
user = request.form['nm']
它作为可变部分传递到‘/success’ URL。浏览器在窗口中显示欢迎消息。
在login.html中将method参数更改为‘GET’,然后在浏览器中再次打开它。服务器接收到的数据是通过GET方法接收的。‘nm’参数的值现在通过以下方式获得:
User = request.args.get(‘nm’)
这里,args是包含表单参数及其对应值对列表的字典对象。与‘nm’参数对应的值像以前一样传递到‘/success’ URL。
Flask – 模板
可以以HTML的形式返回绑定到特定URL的函数的输出。例如,在以下脚本中,hello()函数将呈现‘Hello World’,并附加<h1>标记。
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模板引擎。与其从函数中返回硬编码的HTML,不如使用render_template()函数渲染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文件,该文件夹与包含此脚本的文件夹位于同一目录下。
- 应用程序文件夹
- Hello.py
- templates
- hello.html
术语“Web模板系统”指的是设计一个HTML脚本,其中可以动态插入可变数据。Web模板系统由模板引擎、某种数据源和模板处理器组成。
Flask使用Jinja2模板引擎。Web模板包含HTML语法,其中穿插着变量和表达式的占位符(在本例中为Python表达式),这些占位符在渲染模板时会被替换为值。
以下代码保存在templates文件夹中的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:https://127.0.0.1:5000/hello/mvl
URL中的变量部分插入到{{ name }}占位符中。
Jinja2模板引擎使用以下定界符来转义HTML。
- {% ... %} 用于语句
- {{ ... }} 用于打印到模板输出的表达式
- {# ... #} 用于模板输出中不包含的注释
- # ... ## 用于行语句
在以下示例中,演示了在模板中使用条件语句。到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-else和endif包含在定界符{%..%}中。
运行Python脚本并访问URL https://127.0.0.1/hello/60,然后访问https://127.0.0.1/hello/30,查看HTML输出根据条件变化。
Python循环结构也可以在模板内使用。在以下脚本中,当在浏览器中打开URL https://127.0.0.1:5000/result时,result()函数将字典对象发送到模板results.html。
result.html的模板部分使用for循环将字典对象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脚本保存为templates文件夹中的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和value则放在{{ }}内。
开发服务器启动并运行后,在浏览器中打开https://127.0.0.1:5000/result,即可获得以下输出。
Flask – 静态文件
Web应用程序通常需要静态文件,例如支持网页显示的javascript文件或CSS文件。通常,Web服务器会配置为您提供服务,但在开发过程中,这些文件是从包中的static文件夹或模块旁边的static文件夹提供的服务,它在应用程序中可用/static。
一个特殊的端点“static”用于生成静态文件的URL。
在以下示例中,在index.html中的HTML按钮的OnClick事件上调用在hello.js中定义的javascript函数,该函数在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 – 请求对象
来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应从Flask模块导入它。
请求对象的重要属性如下:
Form – 包含表单参数及其值的键值对的字典对象。
args – 解析后的查询字符串内容,它是问号(?)之后URL的一部分。
Cookies – 保存Cookie名称和值的字典对象。
files – 与上传文件相关的数据。
method – 当前请求方法。
Flask – 将表单数据发送到模板
我们已经看到,可以在URL规则中指定http方法。被触发的函数接收到的Form数据可以以字典对象的格式收集它,并将其转发到模板以在相应的网页上呈现它。
在以下示例中,‘/’ URL呈现一个包含表单的网页(student.html)。其中填写的数据被发布到‘/result’ URL,该URL触发result()函数。
results()函数收集request.form中存在的表单数据到一个字典对象中,并将其发送到result.html进行渲染。
模板动态呈现表单数据的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 = "https://127.0.0.1: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 https://127.0.0.1:5000/。
单击提交按钮时,表单数据将以HTML表格的形式在result.html上呈现。
Flask – Cookies
Cookie以文本文件的形式存储在客户端的计算机上。其目的是记住和跟踪与客户端使用相关的数据,以获得更好的访客体验和网站统计数据。
请求对象包含Cookie的属性。它是客户端已传输的所有Cookie变量及其对应值的字典对象。此外,Cookie还存储其过期时间、路径和站点的域名。
在Flask中,Cookie是在响应对象上设置的。使用make_response()函数从视图函数的返回值获取响应对象。之后,使用响应对象的set_cookie()函数存储Cookie。
读取Cookie很容易。request.cookies属性的get()方法用于读取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。关联的视图函数设置一个名为userID的Cookie并呈现另一个页面。
@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>'
运行应用程序并访问https://127.0.0.1:5000/
设置Cookie的结果显示如下:
读取Cookie的输出如下所示。
Flask – 会话
与Cookie类似,会话数据存储在客户端。会话是指客户端登录服务器并注销服务器的时间间隔。在此会话期间需要保留的数据存储在客户端浏览器中。
为每个客户端分配一个会话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’
输出将如下所示。单击链接“点击此处登录”。
链接将指向另一个屏幕。键入‘admin’。
屏幕将显示消息“已登录为admin”。
Flask – 重定向和错误
Flask类具有redirect()函数。调用时,它返回一个响应对象并将用户重定向到另一个目标位置,并指定状态代码。
redirect()函数的原型如下:
Flask.redirect(location, statuscode, response)
在上述函数中:
location参数是应将响应重定向到的URL。
statuscode发送到浏览器的标头,默认为302。
response参数用于实例化响应。
以下状态代码是标准化的:
- HTTP_300_MULTIPLE_CHOICES
- HTTP_301_MOVED_PERMANENTLY
- HTTP_302_FOUND
- HTTP_303_SEE_OTHER
- HTTP_304_NOT_MODIFIED
- HTTP_305_USE_PROXY
- HTTP_306_RESERVED
- HTTP_307_TEMPORARY_REDIRECT
默认状态代码为302,表示“已找到”。
在以下示例中,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参数采用以下值之一:
400 – 用于错误请求
401 – 用于未经身份验证
403 – 用于禁止访问
404 – 用于未找到
406 – 用于不可接受
415 – 用于不支持的媒体类型
429 – 请求过多
让我们对上述代码中的login()函数做一个小小的修改。如果要显示“未授权”页面,而不是重新显示登录页面,请将其替换为对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 – 消息闪现
一个良好的基于GUI的应用程序会向用户提供有关交互的反馈。例如,桌面应用程序使用对话框或消息框,而JavaScript使用警报来实现类似的目的。
在Flask Web应用程序中生成此类信息性消息很容易。Flask框架的闪现系统使得可以在一个视图中创建消息,并在接下来调用的视图函数中呈现它。
Flask模块包含flash()方法。它将消息传递到下一个请求,通常是模板。
flash(message, category)
这里:
message参数是要闪现的实际消息。
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,该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>
另一方面,如果登录成功,则会在索引模板上闪现成功消息。
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 – 文件上传
在Flask中处理文件上传非常容易。它需要一个HTML表单,其enctype属性设置为“multipart/form-data”,并将文件发布到URL。URL处理程序从request.files[]对象中获取文件并将其保存到所需位置。
每个上传的文件首先保存在服务器上的临时位置,然后才能实际保存到最终位置。目标文件名称可以硬编码,也可以从request.files[file]对象的filename属性获取。但是,建议使用secure_filename()函数获取其安全版本。
可以在Flask对象的配置设置中定义默认上传文件夹的路径和上传文件的最大大小。
app.config[‘UPLOAD_FOLDER’] | 定义上传文件夹的路径 |
app.config[‘MAX_CONTENT_LENGTH’] | 指定要上传的文件的最大大小(以字节为单位) |
以下代码具有‘/upload’ URL规则,该规则显示模板文件夹中的‘upload.html’,以及‘/upload-file’ URL规则,该规则调用处理上传过程的uploader()函数。
‘upload.html’有一个文件选择器按钮和一个提交按钮。
<html> <body> <form action = "https://127.0.0.1:5000/uploader" method = "POST" enctype = "multipart/form-data"> <input type = "file" name = "file" /> <input type = "submit"/> </form> </body> </html>
您将看到如下所示的屏幕。
选择文件后单击提交。表单的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 – 扩展
Flask通常被称为微框架,因为其核心功能包括基于Werkzeug的WSGI和路由以及基于Jinja2的模板引擎。此外,Flask框架还支持cookie和会话以及诸如JSON、静态文件等的Web辅助工具。显然,这不足以开发一个成熟的Web应用程序。这就是Flask扩展发挥作用的地方。Flask扩展为Flask框架提供了可扩展性。
有很多可用的Flask扩展。Flask扩展是一个Python模块,它为Flask应用程序添加特定类型的支持。Flask扩展注册表是一个可用的扩展目录。可以使用pip实用程序下载所需的扩展。
在本教程中,我们将讨论以下重要的Flask扩展:
Flask Mail − 为Flask应用程序提供SMTP接口
Flask WTF − 添加WTForms的渲染和验证
Flask SQLAlchemy − 为Flask应用程序添加SQLAlchemy支持
Flask Sijax − Sijax的接口 - 一个Python/jQuery库,使在Web应用程序中易于使用AJAX
每种类型的扩展通常都提供关于其用法的广泛文档。由于扩展是一个Python模块,因此需要导入它才能使用它。Flask扩展通常命名为flask-foo。要导入,
from flask_foo import [class, function]
对于0.7以后版本的Flask,您也可以使用以下语法:
from flask.ext import foo
对于此用法,需要激活一个兼容性模块。可以通过运行flaskext_compat.py来安装它。
import flaskext_compat flaskext_compat.activate() from flask.ext import foo
Flask – 邮件
基于Web的应用程序通常需要具有向用户/客户端发送邮件的功能。Flask-Mail扩展使得使用任何电子邮件服务器设置简单的接口变得非常容易。
首先,应使用pip实用程序安装Flask-Mail扩展。
pip install Flask-Mail
然后,需要通过设置以下应用程序参数的值来配置Flask-Mail。
序号 | 参数和描述 |
---|---|
1 |
MAIL_SERVER 电子邮件服务器的名称/IP地址 |
2 |
MAIL_PORT 使用的服务器端口号 |
3 |
MAIL_USE_TLS 启用/禁用传输安全层加密 |
4 |
MAIL_USE_SSL 启用/禁用安全套接字层加密 |
5 |
MAIL_DEBUG 调试支持。默认为Flask应用程序的调试状态 |
6 |
MAIL_USERNAME 发件人的用户名 |
7 |
MAIL_PASSWORD 发件人的密码 |
8 |
MAIL_DEFAULT_SENDER 设置默认发件人 |
9 |
MAIL_MAX_EMAILS 设置要发送的最大邮件数 |
10 |
MAIL_SUPPRESS_SEND 如果app.testing设置为true,则抑制发送 |
11 |
MAIL_ASCII_ATTACHMENTS 如果设置为true,则附加文件名将转换为ASCII |
flask-mail模块包含以下重要类的定义。
Mail类
它管理电子邮件消息要求。类的构造函数采用以下形式:
flask-mail.Mail(app = None)
构造函数将Flask应用程序对象作为参数。
Mail类的使用方法
序号 | 方法和描述 |
---|---|
1 |
send() 发送Message类对象的內容 |
2 |
connect() 打开与邮件主机的连接 |
3 |
send_message() 发送消息对象 |
Message类
它封装了一个电子邮件消息。Message类的构造函数有几个参数:
flask-mail.Message(subject, recipients, body, html, sender, cc, bcc, reply-to, date, charset, extra_headers, mail_options, rcpt_options)
Message类的使用方法
attach() − 向消息添加附件。此方法采用以下参数:
filename − 要附加的文件名
content_type − 文件的MIME类型
data − 原始文件数据
disposition − 内容处置(如有)。
add_recipient() − 向消息添加另一个收件人
在以下示例中,Google的gmail服务的SMTP服务器用作Flask-Mail配置的MAIL_SERVER。
步骤1 − 在代码中从flask-mail模块导入Mail和Message类。
from flask_mail import Mail, Message
步骤2 − 然后根据以下设置配置Flask-Mail。
app.config['MAIL_SERVER']='smtp.gmail.com' app.config['MAIL_PORT'] = 465 app.config['MAIL_USERNAME'] = '[email protected]' app.config['MAIL_PASSWORD'] = '*****' app.config['MAIL_USE_TLS'] = False app.config['MAIL_USE_SSL'] = True
步骤3 − 创建Mail类的实例。
mail = Mail(app)
步骤4 − 在由URL规则(‘/’)映射的Python函数中设置Message对象。
@app.route("/") def index(): msg = Message('Hello', sender = '[email protected]', recipients = ['[email protected]']) msg.body = "This is the email body" mail.send(msg) return "Sent"
步骤5 − 完整的代码如下所示。在Python Shell中运行以下脚本,然后访问https://127.0.0.1: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'] = '[email protected]' 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 = '[email protected]', recipients = ['[email protected]']) msg.body = "Hello Flask message sent from Flask-Mail" mail.send(msg) return "Sent" if __name__ == '__main__': app.run(debug = True)
请注意,Gmail服务中的内置安全功能可能会阻止此登录尝试。您可能需要降低安全级别。请登录您的Gmail帐户并访问此链接以降低安全性。
Flask – WTF
Web应用程序的一个重要方面是为用户提供用户界面。HTML提供了一个<form>标签,用于设计界面。可以适当地使用表单元素,例如文本输入、单选按钮、选择等。
用户输入的数据以Http请求消息的形式通过GET或POST方法提交到服务器端脚本。
服务器端脚本必须从http请求数据中重新创建表单元素。因此,实际上,表单元素必须定义两次——一次在HTML中,另一次在服务器端脚本中。
使用HTML表单的另一个缺点是很难(如果不是不可能的话)动态渲染表单元素。HTML本身不提供任何验证用户输入的方法。
这就是WTForms(一个灵活的表单、渲染和验证库)发挥作用的地方。Flask-WTF扩展为此WTForms库提供了一个简单的接口。
使用Flask-WTF,我们可以在Python脚本中定义表单字段,并使用HTML模板渲染它们。也可以对WTF字段应用验证。
让我们看看这个HTML的动态生成是如何工作的。
首先,需要安装Flask-WTF扩展。
pip install flask-WTF
已安装的包包含一个Form类,该类必须用作用户定义表单的父类。
WTforms包包含各种表单字段的定义。一些标准表单字段列在下面。
序号 | 标准表单字段和说明 |
---|---|
1 |
TextField 表示<input type = 'text'> HTML表单元素 |
2 |
BooleanField 表示<input type = 'checkbox'> HTML表单元素 |
3 |
DecimalField 用于显示带有小数的数字的文本字段 |
4 |
IntegerField 用于显示整数的文本字段 |
5 |
RadioField 表示<input type = 'radio'> HTML表单元素 |
6 |
SelectField 表示select表单元素 |
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令牌的隐藏字段。这是为了防止跨站点请求伪造攻击。
渲染后,这将生成如下所示的等效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包还包含validator类。它可用于对表单字段应用验证。以下列表显示了常用的验证器。
序号 | 验证器类和说明 |
---|---|
1 |
DataRequired 检查输入字段是否为空 |
2 |
检查字段中的文本是否符合电子邮件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()函数验证表单数据,如果验证失败则抛出验证错误。错误消息被发送到模板。在HTML模板中,错误消息是动态渲染的。
{% for message in form.name.errors %} {{ message }} {% endfor %}
以下示例演示了上述概念。联系表单的设计如下所示(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")
验证器应用于姓名和电子邮件字段。
以下是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 = "https://127.0.0.1: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并访问URLhttps://127.0.0.1:5000/contact。联系表单将显示如下。
如果出现任何错误,页面将如下所示:
如果没有错误,将呈现‘success.html’。
Flask – SQLite
Python内置支持SQlite。SQLite3模块随Python发行版一起提供。有关在Python中使用SQLite数据库的详细教程,请参阅此链接。在本节中,我们将了解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应用程序具有三个视图函数。
第一个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方法检索表单数据并将其插入学生表中。插入操作成功或失败的消息将呈现到‘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}},该语句显示插入操作的结果。
<!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对象。此对象传递给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运行此脚本,并启动开发服务器。在浏览器中访问https://127.0.0.1:5000/,它将显示如下所示的简单菜单:
单击‘添加新记录’链接以打开学生信息表单。
填写表单字段并提交。底层函数将记录插入学生表中。
返回主页并单击‘显示列表’链接。将显示显示示例数据的表格。
Flask – SQLAlchemy
在Flask Web应用程序中使用原始SQL对数据库执行CRUD操作可能很繁琐。相反,SQLAlchemy是一个Python工具包,是一个强大的OR Mapper,它为应用程序开发人员提供了SQL的全部功能和灵活性。Flask-SQLAlchemy是Flask扩展,它为您的Flask应用程序添加了对SQLAlchemy的支持。
什么是ORM(对象关系映射)?
大多数编程语言平台都是面向对象的。另一方面,RDBMS服务器中的数据存储为表。对象关系映射是一种将对象参数映射到底层RDBMS表结构的技术。ORM API提供执行CRUD操作的方法,而无需编写原始SQL语句。
在本节中,我们将研究Flask-SQLAlchemy的ORM技术并构建一个小型Web应用程序。
步骤1 - 安装Flask-SQLAlchemy扩展。
pip install flask-sqlalchemy
步骤2 - 您需要从此模块导入SQLAlchemy类。
from flask_sqlalchemy import SQLAlchemy
步骤3 - 现在创建一个Flask应用程序对象并设置要使用的数据库的URI。
app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///students.sqlite3'
步骤4 - 然后使用应用程序对象作为参数创建一个SQLAlchemy类的对象。此对象包含用于ORM操作的辅助函数。它还提供一个父模型类,用户定义的模型就是使用它声明的。在下面的代码片段中,创建了一个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
步骤5 - 要创建/使用URI中提到的数据库,请运行create_all()方法。
db.create_all()
SQLAlchemy的Session对象管理ORM对象的所有持久性操作。
以下会话方法执行CRUD操作:
db.session.add(模型对象) - 将记录插入映射表
db.session.delete(模型对象) - 从表中删除记录
model.query.all() - 从表中检索所有记录(对应于SELECT查询)。
您可以使用filter属性对检索到的记录集应用过滤器。例如,为了检索学生表中city = 'Hyderabad'的记录,请使用以下语句:
Students.query.filter_by(city = ’Hyderabad’).all()
有了这些背景知识,现在我们将为我们的应用程序提供视图函数来添加学生数据。
应用程序的入口点是绑定到‘/’ URL的show_all()函数。学生表的记录集作为参数发送到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时,表单数据将添加到students表中,并且应用程序将返回主页并显示已添加的数据。
@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运行脚本,并在浏览器中输入https://127.0.0.1:5000/。
单击‘添加学生’链接以打开学生信息表单。
填写表单并提交。主页将重新出现,其中包含提交的数据。
我们可以看到如下所示的输出。
Flask – Sijax
Sijax代表‘Simple Ajax’,它是一个Python/jQuery库,旨在帮助您轻松地将Ajax引入您的应用程序。它使用jQuery.ajax发出AJAX请求。
安装
Flask-Sijax的安装很简单。
pip install flask-sijax
配置
SIJAX_STATIC_PATH - 您希望镜像Sijax javascript文件的静态路径。默认位置是static/js/sijax。在这个文件夹中,保存了sijax.js和json2.js文件。
SIJAX_JSON_URI - 加载json2.js静态文件的URI
Sijax使用JSON在浏览器和服务器之间传递数据。这意味着浏览器要么需要原生支持JSON,要么从json2.js文件获得JSON支持。
以这种方式注册的函数无法提供Sijax功能,因为默认情况下无法使用POST方法访问它们(而Sijax使用POST请求)。
要使视图函数能够处理Sijax请求,请使用@app.route('/url', methods = ['GET', 'POST'])使其可以通过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应用程序
一个最小的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 – 部署
外部可见服务器
开发服务器上的Flask应用程序只能在设置了开发环境的计算机上访问。这是默认行为,因为在调试模式下,用户可以在计算机上执行任意代码。
如果禁用了debug,可以通过将主机名设置为‘0.0.0.0’来使本地计算机上的开发服务器可供网络上的用户使用。
app.run(host = ’0.0.0.0’)
因此,您的操作系统将监听所有公共IP。
部署
要从开发环境切换到成熟的生产环境,需要将应用程序部署到真实的Web服务器上。根据您的情况,可以使用不同的选项来部署Flask Web应用程序。
对于小型应用程序,您可以考虑将其部署在以下任何托管平台上,所有这些平台都为小型应用程序提供免费计划。
- Heroku
- dotcloud
- webfaction
Flask应用程序可以部署在这些云平台上。此外,还可以将Flask应用程序部署到Google云平台。Localtunnel服务允许您共享localhost上的应用程序,而无需更改DNS和防火墙设置。
如果您倾向于使用专用Web服务器来代替上述共享平台,则可以使用以下选项。
mod_wsgi
mod_wsgi是一个Apache模块,它提供了一个符合WSGI的接口,用于在Apache服务器上托管基于Python的Web应用程序。
安装mod_wsgi
要直接从PyPi安装官方版本,您可以运行:
pip install mod_wsgi
要验证安装是否成功,请使用start-server命令运行mod_wsgi-express脚本:
mod_wsgi-express start-server
这将在端口8000上启动Apache/mod_wsgi。然后,您可以通过将浏览器指向以下地址来验证安装是否成功:
https://127.0.0.1:8000/
创建.wsgi文件
应该有一个yourapplication.wsgi文件。此文件包含mod_wsgi代码,该代码在启动时执行以获取应用程序对象。对于大多数应用程序,以下文件应该足够了:
from yourapplication import app as application
确保yourapplication和所有正在使用的库都在python加载路径上。
配置Apache
您需要告诉mod_wsgi您的应用程序的位置。
<VirtualHost *> ServerName example.com WSGIScriptAlias / C:\yourdir\yourapp.wsgi <Directory C:\yourdir> Order deny,allow Allow from all </Directory> </VirtualHost>
独立WSGI容器
有很多流行的用Python编写的服务器包含WSGI应用程序并提供HTTP服务。
- Gunicorn
- Tornado
- Gevent
- Twisted Web
Flask – FastCGI
FastCGI是将Flask应用程序部署到nginx、lighttpd和Cherokee等Web服务器上的另一个选项。
配置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()
配置Apache
对于基本的Apache部署,您的.fcgi文件将出现在您的应用程序URL中,例如example.com/yourapplication.fcgi/hello/。有几种方法可以配置您的应用程序,以便yourapplication.fcgi不会出现在URL中。
<VirtualHost *> ServerName example.com ScriptAlias / /path/to/yourapplication.fcgi/ </VirtualHost>
配置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。