😅

Flash

项目地址

概述

flask:
Flask是一个用Python编写的Web应用程序框架。 它由 Armin Ronacher 开发,他领导一个名为Pocco的国际Python爱好者团队。 Flask基于Werkzeug WSGI工具包和Jinja2模板引擎。两者都是Pocco项目。
werkzeug:
它是一个WSGI工具包,它实现了请求,响应对象和实用函数。 这使得能够在其上构建web框架。 Flask框架使用Werkzeug作为其基础之一。
jinja2:
jinja2是Python的一个流行的模板引擎。Web模板系统将模板与特定数据源组合以呈现动态网页。
Flask通常被称为微框架。 它旨在保持应用程序的核心简单且可扩展。Flask没有用于数据库处理的内置抽象层,也没有形成验证支持。相反,Flask支持扩展以向应用程序添加此类功能。一些受欢迎的Flask扩展将在本教程后续章节进行讨论。

应用

from flask import Flask app = Flask(__name__) @app.route('/') def hello_world(): return 'Hello World' if __name__ == '__main__': app.run()
Flask类的对象是WSGI应用程序,通过__call_方法调用了wsgi_app()方法,该方法完成了请求和响应的处理,WSGI服务器通过调用该方法传入请求数据,获取返回数据
Flask构造函数使用当前模块(__name __)的名称作为参数。
Flask类的route()函数是一个装饰器,它告诉应用程序哪个URL应该调用相关的函数。
  • rule 参数表示与该函数的URL绑定。
  • options 是要转发给基础Rule对象的参数列表。

路由

#route()装饰器用于将URL绑定到函数 @app.route("/hello") def hello_world(): return 'hello world' #application对象的add_url_rule()函数也可用于将URL将函数绑定 def hello_world(): return 'hello world' app.add_url_rule('/','hello',hello_world)
注意:装饰器在脚手架类Scaffold中定义,Flask类继承自Scaffold类

变量规则

Flask的url变量规则基于Werkzeug的路由模块,通过向route规则参数中添加变量部分,可以动态构建URL,此变量部分标记为<variable-name>,作为关键字参数传递给与规则相关联的函数
@app.route('/hello/<name>') def hello_name(name): return 'Hello %s!' % name
除了默认字符串变量之外,还可以使用以下转化器构造规则
序号
转换器
描述
1
int
接受整数
2
float
对于浮点值
3
path
接受用作目录分隔符的斜杠
@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

URL构建

url_for()函数对于动态构建特定函数的URL非常有用。
url_for()函数接受函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应于URL的变量部分。
@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))
上述脚本有一个函数hello_user(name),它接受来自URL的参数的值。
hello_user()函数检查接收的参数是否与'admin'匹配。
如果匹配,则使用url_for()将应用程序重定向到hello_admin()函数,否则重定向到将接收的参数作为guest参数传递给它的hello_guest()函数。

HTTP方法

默认情况下,Flask路由响应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项。
from flask import Flask, redirect, url_for, request, render_template app = Flask(__name__) @app.route('/') def index(): return render_template("login.html") @app.route('/success/<name>') def success(name): return 'welcome %s' % name @app.route('/login',methods = ['POST', 'GET']) def login(): if request.method == 'POST': print(1) user = request.form['nm'] return redirect(url_for('success',name = user)) else: print(2) user = request.args.get('nm') return redirect(url_for('success',name = user)) if __name__ == '__main__': app.run()
post请求,通过request.form(’name’)解析表单中的值
get请求,通过request.args.get(’name‘)解析表单中的值

模板

视图函数有两个作用:
  • 处理业务逻辑
  • 返回响应内容
在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本.
  • 模板其实是一个包含响应文本的文件,其中用占位符(变量)表示动态部分,告诉模板引擎其具体的值需要从使用的数据中获取
  • 使用真实值替换变量,再返回最终得到的字符串,这个过程称为'渲染'
  • Flask 是使用 Jinja2 这个模板引擎来渲染模板
使用模板的好处
  • 视图函数只负责业务逻辑和数据处理(业务逻辑方面)
  • 而模板则取到视图函数的数据结果进行展示(视图展示方面)
  • 代码结构清晰,耦合度低
基本使用:
在项目下创建 templates 文件夹,用于存放所有模板文件,并在目录下创建一个模板文件 html 文件 hello.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 我的模板html内容 </body> </html>
创建视图函数,将该模板内容进行渲染返回
from flask import Flask, render_template app = Flask(__name__) @app.route('/') def index(): return render_template('hello.html')
模板变量:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 我的模板html内容 <br />{{ my_str }} <br />{{ my_int }} <br />{{ my_array }} <br />{{ my_dict }} </body> </html>
代码中传入字符串、列表、字典到模板中
@app.route('/') def index(): # 往模板中传入的数据 my_str = 'Hello Word' my_int = 10 my_array = [3, 4, 2, 1, 7, 9] my_dict = { 'name': 'xiaoming', 'age': 18 } return render_template('hello.html', my_str=my_str, my_int=my_int, my_array=my_array, my_dict=my_dict )

静态文件

Web应用程序通常需要静态文件,例如javascript文件或支持网页显示的CSS文件。
通常,配置Web服务器并为您提供这些服务,但在开发过程中,这些文件是从您的包或模块旁边的static文件夹中提供,它将在应用程序的/static中提供。
特殊端点'static'用于生成静态文件的URL。
在下面的示例中,在index.html中的HTML按钮的OnClick事件上调用hello.js中定义的javascript函数,该函数在Flask应用程序的“/”URL上呈现。
@app.route("/") def index(): return render_template("index.html") if __name__ == '__main__': app.run(debug = True)
<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>
function sayHello() { alert("Hello World") }

Request对象

Request对象的重要属性如下所列:
  • Form - 它是一个字典对象,包含表单参数及其值的键和值对。
  • args 解析查询字符串的内容,它是问号(?)之后的URL的一部分。
  • Cookies  - 保存Cookie名称和值的字典对象。
  • files - 与上传文件有关的数据。
  • method - 当前请求方法。

表单数据

访问主页/后返回student.html页面,填写完表单信息后发起post请求
route解析到result函数获取表单数据result并填入模板result.html中
@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)
<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>
<!doctype html> <table border = 1> {% for key, value in result.items() %} <tr> <th> {{ key }} </th> <td> {{ value }}</td> </tr> {% endfor %} </table>

Cookies

需要导入make_response
  1. 设置cookie:
    1. 设置cookie,默认有效期是临时cookie,浏览器关闭就失效
      可以通过 max_age 设置有效期, 单位是秒
  1. 获取cookie
    1. 获取cookie,通过request.cookies的方式, 返回的是一个字典,可以获取字典里的相应的值
  1. 删除cookie
这里的删除只是让cookie过期,并不是直接删除cookie 删除cookie,通过delete_cookie()的方式, 里面是cookie的名字
from flask import Flask, make_response, request # 注意需导入 make_response app = Flask(__name__) @app.route("/set_cookies") def set_cookie(): resp = make_response("success") resp.set_cookie("w3cshool", "w3cshool",max_age=3600) return resp @app.route("/get_cookies") def get_cookie(): cookie_1 = request.cookies.get("w3cshool") # 获取名字为Itcast_1对应cookie的值 return cookie_1 @app.route("/delete_cookies") def delete_cookie(): resp = make_response("del success") resp.delete_cookie("w3cshool") //字典中还有key但没有value return resp

会话

与Cookie不同,Session(会话)数据存储在服务器上。会话是客户端登录到服务器并注销服务器的时间间隔。需要在该会话中保存的数据会存储在服务器上的临时目录中。
为每个客户端的会话分配会话ID。会话数据存储在cookie的顶部,服务器以加密方式对其进行签名。对于此加密,Flask应用程序需要一个定义的SECRET_KEY
from flask import render_template from flask import make_response from flask import Flask, session, redirect, url_for, escape, request app = Flask(__name__) app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj' @app.route('/') def index(): if 'username' in session: username = session['username'] return '登录用户名是:' + username + '<br>' + \ "<b><a href = '/logout'>点击这里注销</a></b>" return "您暂未登录, <br><a href = '/login'></b>" + \ "点击这里登录</b></a>" @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 ="登录"/></p> </form> ''' @app.route('/logout') def logout(): # remove the username from the session if it is there session.pop('username', None) return redirect(url_for('index')) if __name__ == '__main__': app.run(debug = True)

重定向和错误

lask类有一个redirect()函数。调用时,它返回一个响应对象,并将用户重定向到具有指定状态代码的另一个目标位置。
redirect()函数的原型如下:
Flask.redirect(location, statuscode, response)
在上述函数中:
  • location参数是应该重定向响应的URL。
  • statuscode发送到浏览器标头,默认为302。
  • response参数用于实例化响应。
@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')) return redirect(url_for('index')) @app.route('/success') def success(): return 'logged in successfully'
Flask类具有带有错误代码的abort()函数。
Flask.abort(code)
Code 参数采用以下值之一:
  • 400 用于错误请求
  • 401 用于未身份验证的
  • 403 Forbidden
  • 404 未找到
  • 406 表示不接受
  • 415 用于不支持的媒体类型
  • 429 请求过多
@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'

消息闪现

Flask 提供了一个非常简单的方法来使用闪现系统向用户反馈信息。闪现系统使得在一个请求结束的时候记录一个信息,并且在下次(且仅在下一次中)请求时访问它,这通常与布局模板结合使用以公开信息。
在 Flask Web 应用程序中生成这样的信息性消息很容易。Flask 框架的闪现系统可以在一个视图中创建消息,并在名为 next 的视图函数中呈现它。
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 中处理文件上传非常简单。它需要一个 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'] 指定要上传的文件的最大大小(以字节为单位)
from flask import Flask, render_template, request from werkzeug.utils import secure_filename import os app = Flask(__name__) app.config['UPLOAD_FOLDER'] = 'upload/' @app.route('/upload') def upload_file(): return render_template('upload.html') @app.route('/uploader',methods=['GET','POST']) def uploader(): if request.method == 'POST': f = request.files['file'] print(request.files) //request.files[file].filename f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename))) return 'file uploaded successfully' else: return render_template('upload.html')

拓展和寻找拓展

Flask=wekzeug的WSGI和路由+jinja2模板引擎+json,静态文件等web帮助程序
常用的拓展包:
Flask-SQLalchemy:操作数据库;
Flask-script:插入脚本;
Flask-migrate:管理迁移数据库;
Flask-Session:Session存储方式指定;
Flask-WTF:表单;
Flask-Mail:邮件;
Flask-Bable:提供国际化和本地化支持,翻译;
Flask-Login:认证用户状态;
Flask-OpenID:认证;
Flask-RESTful:开发REST API的工具;
Flask-Bootstrap:集成前端Twitter Bootstrap框架;
Flask-Moment:本地化日期和时间;
Flask-Admin:简单而可扩展的管理接口的框架
使用拓展:
from flask_foo import Foo foo = Foo() app = Flask(__name__) app.config.update( FOO_BAR='baz', FOO_SPAM='eggs', ) foo.init_app(app)

邮件

安装Flask-Mail拓展
pip install Flask-Mail
Mail类:管理电子邮件消息传递需求,类构造函数采用以下形式
flask-mail.Mail(app = None)
Message类:封装电子邮件
flask-mail.Message(subject, recipients, body, html, sender, cc, bcc, reply-to, date, charset, extra_headers, mail_options, rcpt_options)
from flask import Flask from flask_mail import Mail, Message app =Flask(__name__) 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"

WTF+SQLite+SQLALchemy

WTF:
Web应用程序的一个重要方面是为用户提供用户界面。HTML提供了一个<form>标签,用于设计界面。
可以适当地使用Form(表单) 元素,例如文本输入,单选按钮,选择等。
用户输入的数据以Http请求消息的形式通过GET或POST方法提交给服务器端脚本。
  • 服务器端脚本必须从http请求数据重新创建表单元素。因此,实际上,表单元素必须定义两次 - 一次在HTML中,另一次在服务器端脚本中。
  • 使用HTML表单的另一个缺点是很难(如果不是不可能的话)动态呈现表单元素。HTML本身无法验证用户的输入。
这就是WTForms的作用,一个灵活的表单,渲染和验证库,能够方便使用。
Flask-WTF扩展为这个WTForms库提供了一个简单的接口。
使用Flask-WTF,我们可以在Python脚本中定义表单字段,并使用HTML模板进行渲染。还可以将验证应用于WTF字段。
基本使用
已安装的软件包包含一个Form类,该类必须用作用户定义表单的父级。
WTforms包中包含各种表单字段的定义
from flask_wtf import Form from wtforms import TextField class ContactForm(Form): name = TextField("Name Of Student")
在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包也包含验证器类。它对表单字段应用验证很有用
name = TextField("Name Of Student",[validators.Required("Please enter your name.")])
SQLite
在 Flask 中,通过使用特殊的 g 对象可以使用 before_request() 和 teardown_request() 在请求开始前打开数据库连接,在请求结束后关闭连接。
以下是一个在 Flask 中使用 SQLite 3 的例子:
import sqlite3 from flask import g DATABASE = '/path/to/database.db' def connect_db(): return sqlite3.connect(DATABASE) @app.before_request def before_request(): g.db = connect_db() @app.teardown_request def teardown_request(exception): if hasattr(g, 'db'): g.db.close()
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)
SQLALchemy:
在Flask Web应用程序中使用原始SQL对数据库执行CRUD操作可能很繁琐。相反, SQLAlchemy ,Python工具包是一个强大的OR Mapper,它为应用程序开发人员提供了SQL的全部功能和灵活性。Flask-SQLAlchemy是Flask扩展,它将对SQLAlchemy的支持添加到Flask应用程序中。
什么是ORM(Object Relation Mapping,对象关系映射)?
大多数编程语言平台是面向对象的。另一方面,RDBMS服务器中的数据存储为表。
对象关系映射是将对象参数映射到底层RDBMS表结构的技术。
ORM API提供了执行CRUD操作的方法,而不必编写原始SQL语句。
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)
Sijax
Sijax代表'Simple Ajax',它是一个Python/jQuery库,旨在帮助您轻松地将Ajax引入到您的应用程序。它使用jQuery.ajax来发出AJAX请求。
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)

部署:

要从开发环境切换到成熟的生产环境,需要在真实的Web服务器上部署应用程序。根据您的具体情况,可以使用不同的选项来部署Flask Web应用程序。
mod_wsgi:
安装mod_wsgi
pip install mod_wsgi
要验证安装是否成功,请使用start-server命令运行mod_wsgi-express脚本:
mod_wsgi-express start-server
将在端口8000启动Apache/mod_wsgi
创建.wsgi文件
应该有一个yourapplication.wsgi文件。此文件包含代码mod_wsgi,该代码在启动时执行以获取应用程序对象。
对于大多数应用程序,以下文件应该足够了:
from yourapplication import app as application
配置Apache
需要告诉mod_wsgi,您的应用程序的位置:
<VirtualHost *> ServerName example.com WSGIScriptAlias / C:\yourdir\yourapp.wsgi <Directory C:\yourdir> Order deny,allow Allow from all </Directory> </VirtualHost>
FastCGI:
FastCGI是在nginx,lighttpd和Cherokee等web服务器上的Flask应用程序的另一个部署选项。
配置FastCGI
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
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" )