Flask简介
二言以蔽之:小而精,一切皆导入
一、一个简单的Flask案例
1:创建项目
2:安装flask
pip install flask
3:三行代码
from flask import Flask
app=Flask(__name__)
app.run()
4:HelloWorld
from flask import Flask app=Flask(__name__) @app.route("/") def index(): return "Hello,World!!!" app.run(debug=True)
5:总结
- run方法,表示程序运行 app.run(host="0.0.0.0",port=9527,debug=True) #debug=True后,修改完代码会自动重启程序
- @app.route("/HttpResponse") 表示设置路由
二、Response
1:Response三剑客
- HttpResponse
- render
- redirect
2:HttpResponse
from flask import Flask app=Flask(__name__) @app.route("/HttpResponse") def HttpResponse(): return "我是:HttpResponse" app.run(debug=True)
3:render
1:引入模板
from flask import render_template
2:设置语言类型
3:创建模板 选择语言类型jinja2
3:代码
from flask import Flask from flask import render_template app = Flask(__name__, template_folder='../templates') @app.route("/render") def render(): return render_template("render.html") app.run(debug=True)
templates文件夹下的代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>我是Render请求</h1> </body> </html>
4:总结
- app = Flask(__name__, template_folder='../templates'). 可以指定文件模板路径
4:redirect
1:引入模板
from flask import redirect
from flask import Flask from flask import redirect app = Flask(__name__) @app.route("/redire") def redire(): return redirect("/HttpResponse") @app.route("/HttpResponse") def HttpResponse(): return "我是跳转过来的:Redirect " app.run(debug=True)
5:jsonify
1:引入模板
from flask import jsonify
from flask import Flask app = Flask(__name__) @app.route("/json") def json(): return jsonify("{'name':'张三','age':16}") app.run(debug=True)
2:总结
- 封装了Content-Type:application/json
6:send_file
from flask import Flask from flask import send_file app = Flask(__name__) @app.route("/sendfile") def sendfile(): return send_file("../Files/2.mp4") #可以传输mp4 # return send_file("../Files/Chrysanthemum.jpg") #可以传输图片 app.run(debug=True)
三、Request
1:准备一个登录的前后端交互页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> <p>用户名:<input name="username" id="username"></p> <p>密码:<input name="pwd" id="password" type="password"></p> <p> <input type="submit"></p> </form> </body> </html>
from flask import Flask from flask import render_template,request app=Flask(__name__,template_folder="../templates") @app.route("/login",methods=("GET","POST")) def login(): if request.method=="GET": return render_template("login.html") else: reValues=request.form.to_dict() return reValues app.run()
2:准备一个上传文件的前后端交互页面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post" enctype="multipart/form-data"> <p><input type="file" name="fl"></p> <p> <input type="submit" value="提交"></p> </form> </body> </html>
from flask import Flask from flask import render_template,request app=Flask(__name__,template_folder="../templates") @app.route("/fileup",methods=("GET","POST")) def fileup(): if request.method=="GET": return render_template("fileup.html") else: my_file=request.files.get("fl") my_file.save(my_file.filename) return "保存成功!" app.run()
3:总结
-
问题一:如何让一个方法既能接收Post又能接收Get
答:route装饰器的methods参数 - 问题二:如何判断当前请求是GET还是POST
答:通过request.method - 问题三:如何接收客户端传递过来的参数(get传参和post传参)
答:通过request接收参数,from flask import request;
如果是接收地址栏的get参数用request.args、
如果是接收post传递的表单参数用request.form
如果是接收post传递的json参数用request.json
如果是接收post传递的但是无法通过Content-Type解析的参数用request.date
还可以通过request.values既可以获取get参数又可以获取post参数,但是需要注意如果有相同参数,会被覆盖 - 问题四:获取的参数都是什么类型
答:ImmutableMultiDict 可以通过.to_dict() 转换成字典格式 - 问题五:如何获取的路径
当前的url路径 print(request.path)# /req
当前url路径的上一级路径 print(request.script_root) #
当前url的全部路径 print(request.url) # http://127.0.0.1:5000/req
当前url的路径的上一级全部路径 print(request.url_root ) # http://127.0.0.1:5000/ - 问题六:获取的上传文件用什么
答:files - 问题七:其他
获取浏览器cookie request.cookies
获取本次请求的请求头 request.headres
四、jinja2模板语言
1:传递一个字典对象
2:传递一个字典对象组成的列表
3:传递一个字典对象组成的字典
from flask import Flask from flask import render_template, request app = Flask(__name__, template_folder="../templates") @app.route("/student", methods=("GET", "POST")) def student(): STUDENT = {'name': '张三', 'age': 33, 'sex': '保密'} STUDENT_LIST = [ {'name': '张三', 'age': 33, 'sex': '保密'}, {'name': '李四', 'age': 44, 'sex': '男'}, {'name': '王五', 'age': 55, 'sex': '女'}, ] STUDENT_DICT = { 1: {'name': '张三', 'age': 33, 'sex': '保密'}, 2: {'name': '李四', 'age': 44, 'sex': '男'}, 3: {'name': '王五', 'age': 55, 'sex': '女'}, } if request.method == "GET": return render_template("student.html", student=STUDENT, student_list=STUDENT_LIST, student_dict=STUDENT_DICT) else: return "Hello!" app.run()
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 <table border="1px"> 9 <tr> 10 <td>{{ student.name }}</td> 11 <td>{{ student["age"] }}</td> 12 <td>{{ student.get("sex") }}</td> 13 </tr> 14 </table> 15 16 <table border="1xp"> 17 {% for stu in student_list %} 18 <tr> 19 <td>{{ stu }}</td> 20 <td>{{ stu.name }}</td> 21 <td>{{ stu.get("age") }}</td> 22 <td>{{ stu["sex"] }}</td> 23 </tr> 24 {% endfor %} 25 </table> 26 27 <table border="1xp"> 28 {% for stu in student_dict %} 29 <tr> 30 <td>{{ stu }}</td> 31 <td>{{ student_dict.get(stu).name }}</td> 32 <td>{{ student_dict[stu].get("age") }}</td> 33 <td>{{ student_dict[stu]["sex"] }}</td> 34 </tr> 35 {% endfor %} 36 </table> 37 </body> 38 </html>
4:后台传递过来标签语言正常显示
from flask import Flask from flask import Markup from flask import render_template,request app=Flask(__name__,template_folder="../templates") @app.route("/inputTag",methods=("GET","POST")) def inputTag(): str1="<input value='标签一'>" str2=Markup("<input value='标签二'>") return render_template("inputTag.html",str1= str1,str2=str2) app.run(debug=True)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ str1 }} {{ str2 }} {{ str1|safe }} </body> </html>
两种处理方式
1:后台通过Markup处理
2:前台通过 { | safe}处理
5:前台调用后台方法
from flask import Flask from flask import render_template, request app = Flask(__name__, template_folder="../templates") @app.template_global() def getSum(a,b): return a+b @app.template_filter() def getMul(a,b): return a*b @app.route("/globalfunc",methods=("GET","POST")) def globalFunc(): return render_template("globalfunc.html") app.run()
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>{{ getSum(100,200) }}</h1> <h1>{{ 100| getMul(200)}}</h1> </body> </html>
两种处理方式
1:定义一个函数,把它传递给前端
2:通过装饰器定义一个全局函数
2.1 @app.template_global() # 定义全局模板函数
2.2 @app.template_filter() # 定义全局模板函数
6:模板之间代码复用
1:直接把一个页面包含进来 {% include "index.html" %}
2:母页面挖坑+子页面
母页面:{% block content %} {% endblock %}
子页面:{% extends "母页面.html" %} {% block content %} 自己内容 {% endblock %}
7:宏定义
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% macro type_text(name,type) %} <input type="{{ type }}" name="{{ name }}" value="{{ name }}"> {% endmacro %} <h2>在下方是使用宏来生成input标签</h2> {{ type_text("one","text") }} {{ type_text("two","text") }} </body> </html>
8:session
我们再回到Request中的登录页面
from flask import Flask from flask import render_template,request,redirect from flask import session app=Flask(__name__,template_folder="../templates") # 1:导入session模块 # 2:设置 secret_key 来加密字符串的 app.secret_key="Hello,Session" @app.route("/login",methods=("GET","POST")) def login(): if request.method=="GET": return render_template("login.html") else: User={"name":"aaron","pwd":"123"} if request.form.get("username")==User.get("name") and request.form.get("pwd")==User.get("pwd"): # 登录成功后,将登录信息记录到session中 session["user"]=User.get("name") return redirect("/student_index") else: session["user"]=None return "登录失败!" @app.route("/student_index") def studentIndex(): username=session.get("user") if username: return "Hello! "+username else: return redirect("/login")
session使用的过程
1:导入session模块
2:设置 secret_key 来加密字符串的
3:如果登录成功,设置值。否则清空session
4:跳转到 student_index 页面时候,先判断session是否有值
9:通过装饰器设置权限
from flask import Flask from flask import render_template,request,redirect from flask import session app=Flask(__name__,template_folder="../templates") # 1:导入session模块 # 2:设置 secret_key 来加密字符串的 app.secret_key="Hello,Session" @app.route("/login",methods=("GET","POST")) def login(): if request.method=="GET": return render_template("login.html") else: User={"name":"aaron","pwd":"123"} if request.form.get("username")==User.get("name") and request.form.get("pwd")==User.get("pwd"): # 登录成功后,将登录信息记录到session中 session["user"]=User.get("name") return redirect("/student_index") else: session["user"]=None return "登录失败!" @app.route("/student_index") def studentIndex(): username=session.get("user") if username: return "Hello! "+username else: return redirect("/login") # 定义一个装饰器,用于判断权限 def is_loggin(func): def warpper(*args,**kwargs): username = session.get("user") if username: return func(*args,**kwargs) else: return redirect("/login") return warpper @app.route("/student_index2") @is_loggin def studentIndex(): return "Hello! 装饰器" app.run(debug=True)
但是需要注意的是:装饰器如果使用多次的话,需要添加endpoint。该字段可以反向得出路由名称
from flask import Flask from flask import render_template,request,redirect from flask import session app=Flask(__name__,template_folder="../templates") # 1:导入session模块 # 2:设置 secret_key 来加密字符串的 app.secret_key="Hello,Session" @app.route("/login",methods=("GET","POST")) def login(): if request.method=="GET": return render_template("login.html") else: User={"name":"aaron","pwd":"123"} if request.form.get("username")==User.get("name") and request.form.get("pwd")==User.get("pwd"): # 登录成功后,将登录信息记录到session中 session["user"]=User.get("name") return redirect("/student_index") else: session["user"]=None return "登录失败!" @app.route("/student_index") def studentIndex(): username=session.get("user") if username: return "Hello! "+username else: return redirect("/login") # 定义一个装饰器,用于判断权限 def is_loggin(func): def warpper(*args,**kwargs): username = session.get("user") if username: return func(*args,**kwargs) else: return redirect("/login") return warpper @app.route("/student_index2",endpoint="student_index2") @is_loggin def studentIndex2(): return "Hello studentIndex2! 装饰器" @app.route("/student_index3",endpoint="student_index3") @is_loggin def studentIndex3(): return "Hello studentIndex3! 装饰器" app.run(debug=True)
五、Flask中的路由系统
1:methods
作用:设置路由函数允许访问的请求方式
示例:@app.route("/login",methods=("GET","POST"))
参数类型:1:如果不设置methods,那么默认参数为“GET”
2:可以是一个列表、数组
2:endpoint
作用:url_for是通过endpoint查询url地址,然后找视图函数。反向地址,类似django中urls设置路由时的‘name’属性
示例:@app.route("/student_index2",endpoint="student_index2")
参数类型:1:默认与函数名相同
2:可以自定义字符串
特点:1:将名字复杂的函数名利用endpoint简单命名
2:url_for反向访问地址时,是动态获取路由的。当修改某个函数的访问路由名称时,不会影响网页之间的跳转,实现动态获取路由名称,方便提高效率和维护
3:defaults
作用:视图函数的参数默认值
示例:@app.route("/index",defaults={"nid": 18})
参数类型:1:字典
注意点:设置了默认参数,视图中就一定要接收。设置几个接收几个
from flask import Flask app=Flask(__name__) @app.route("/index",defaults={"nid":18,"name":"张三"}) def index(nid,name): #需要注意的是设置了默认参数,视图中就一定要接收 return "Hello! Flask 的 Route。" app.run(debug=True)
4:strict_slashes
作用:url地址的严格匹配
示例:@app.route("/index",strict_slashes=False)
参数类型:1:strict_slashes 默认为True,表示请求地址严格匹配 http://127.0.0.1:5000/index/ 这种以“/”结尾的无法匹配成功
2:strict_slashes 默认为False,以“/”结尾的仍然可以匹配成功
from flask import Flask app=Flask(__name__) @app.route("/index",strict_slashes=False) def index(): return "Hello Route 的 strict_slashes" @app.route("/index2",strict_slashes=True) def index2(): return "Hello Route 的 strict_slashes" app.run(debug=True)
5:redirect_to
作用:url地址重定向
示例:@app.route("/index",redirect_to="/index2")
参数类型:redirect_to 指向一个新的路由地址
from flask import Flask app=Flask(__name__) @app.route("/index",redirect_to="/index2") def index(): return "Hello Route 的 redirect_to" @app.route("/index2") def index2(): return "Hello Route 的 redirect_to.I'm New index" app.run(debug=True)
6:动态参数路由
作用:路由的动态参数,相当于django中的路由(),正则匹配
示例:@app.route("/index/<int:year>/<name>",)
参数类型:1:<>中默认为str类型
2:如果指定类型,传递需要传递相应类型的数据
3:如果默认值和冬天参数类型名一致,默认值会覆盖传递的动态参数值
from flask import Flask app=Flask(__name__) @app.route("/index/<int:year>/<name>",) def index(year,name): #需要注意的是设置了动态参数,视图中就一定要接收 return f"Hello! {name} 的 Happy New {year}。" @app.route("/index2/<int:year>/<name>",defaults={"year":2019,"name":"张三"}) def index2(year,name): #需要注意的是设置了动态参数,视图中就一定要接收 return f"Hello! {name} 的 Happy New {year}。" app.run(debug=True)
六、Flask实例化参数
1:import_name
作用:设置模块名称
示例:app = Flask(__name__)
参数类型:1:正常情况下使用__name__
2:template_folder
作用:template模板目录
示例:app = Flask(__name__, template_folder='../templates')
参数类型:1:默认当前项目中的 templates 目录
2:可以指定相应的模板地址
3:static_folder
作用:静态文件目录
示例:app = Flask(__name__,static_folder = 'static')
参数类型:1:默认当前项目中的 static目录
from flask import Flask from flask import render_template app = Flask(__name__,static_folder = 'static') @app.route("/static") def staticTest(): return render_template("static.html") app.run(debug=True)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <img src="/static/1.jpg"> </body> </html>
注意:如果现在想把文件夹static名字改成statics。那么需要修改三处
1:文件夹名称
2:后台代码实例化 app = Flask(__name__,static_folder = 'static')
3:前端html页面
4:static_url_path
作用:静态文件目录的url路径 远程静态文件时复用
示例:app = Flask(__name__,static_folder = 'static',static_url_path = None,)
参数类型:1:默认与static_folder同名
2:其格式为路由格式
from flask import Flask from flask import render_template app = Flask(__name__,static_folder = 'statics',static_url_path='/static') @app.route("/static") def staticTest(): return render_template("static.html") app.run(debug=True)
同样的,我们把static文件夹修改为statics,只需要修改两个文件
七、Flask对象参数配置
1:secret_key
作用:设置session的Key值
示例:app.secret_key="Hello,Session"
2:其他配置
{ 'DEBUG': False, # 是否开启Debug模式 'TESTING': False, # 是否开启测试模式 'PROPAGATE_EXCEPTIONS': None, # 异常传播(是否在控制台打印LOG) 当Debug或者testing开启后,自动为True 'PRESERVE_CONTEXT_ON_EXCEPTION': None, # 一两句话说不清楚,一般不用它 'SECRET_KEY': None, # 之前遇到过,在启用Session的时候,一定要有它 'PERMANENT_SESSION_LIFETIME': 31, # days , Session的生命周期(天)默认31天 'USE_X_SENDFILE': False, # 是否弃用 x_sendfile 'LOGGER_NAME': None, # 日志记录器的名称 'LOGGER_HANDLER_POLICY': 'always', 'SERVER_NAME': None, # 服务访问域名 'APPLICATION_ROOT': None, # 项目的完整路径 'SESSION_COOKIE_NAME': 'session', # 在cookies中存放session加密字符串的名字 'SESSION_COOKIE_DOMAIN': None, # 在哪个域名下会产生session记录在cookies中 'SESSION_COOKIE_PATH': None, # cookies的路径 'SESSION_COOKIE_HTTPONLY': True, # 控制 cookie 是否应被设置 httponly 的标志, 'SESSION_COOKIE_SECURE': False, # 控制 cookie 是否应被设置安全标志 'SESSION_REFRESH_EACH_REQUEST': True, # 这个标志控制永久会话如何刷新 'MAX_CONTENT_LENGTH': None, # 如果设置为字节数, Flask 会拒绝内容长度大于此值的请求进入,并返回一个 413 状态码 'SEND_FILE_MAX_AGE_DEFAULT': 12, # hours 默认缓存控制的最大期限 'TRAP_BAD_REQUEST_ERRORS': False, # 如果这个值被设置为 True ,Flask不会执行 HTTP 异常的错误处理,而是像对待其它异常一样, # 通过异常栈让它冒泡地抛出。这对于需要找出 HTTP 异常源头的可怕调试情形是有用的。 'TRAP_HTTP_EXCEPTIONS': False, # Werkzeug 处理请求中的特定数据的内部数据结构会抛出同样也是“错误的请求”异常的特殊的 key errors 。 # 同样地,为了保持一致,许多操作可以显式地抛出 BadRequest 异常。 # 因为在调试中,你希望准确地找出异常的原因,这个设置用于在这些情形下调试。 # 如果这个值被设置为 True ,你只会得到常规的回溯。 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', # 生成URL的时候如果没有可用的 URL 模式话将使用这个值 'JSON_AS_ASCII': True, # 默认情况下 Flask 使用 ascii 编码来序列化对象。如果这个值被设置为 False , # Flask不会将其编码为 ASCII,并且按原样输出,返回它的 unicode 字符串。 # 比如 jsonfiy 会自动地采用 utf-8 来编码它然后才进行传输。 'JSON_SORT_KEYS': True, #默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。 # 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。 # 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。 'JSONIFY_PRETTYPRINT_REGULAR': True, 'JSONIFY_MIMETYPE': 'application/json', 'TEMPLATES_AUTO_RELOAD': None, }
3:如何查看系统默认配置
self.config = self.make_config(instance_relative_config)
defaults = dict(self.default_config)
八、Flask设置不同环境下的对象参数配置
1:创建一个专门配置不同环境的setting文件
class DEBUGEVN(object): DEBUG=True SECRET_KEY="DEBUGER" SESSION_COOKIE_NAME="DEBUG" class TESTEVN(object): TESTING=True SECRET_KEY="TEST" SESSION_COOKIE_NAME="TEST" class PRODUCTEVN(object): SECRET_KEY="PRODUCT" SESSION_COOKIE_NAME="PRODUCT"
2:使用的时候通过
app.config.from_object(setting.PRODUCTEVN)
from flask import Flask from flask import render_template,session from app import setting app = Flask(__name__,static_folder = 'statics', static_url_path='/static') app.config.from_object(setting.PRODUCTEVN) @app.route("/setting") def settingTest(): session["user"]="1" return render_template("static.html") app.run(debug=True)
九、蓝图Blueprint
1:啥是蓝图
简单来说,Blueprint 是一个存储操作方法的容器,这些操作在这个Blueprint 被注册到一个应用之后就可以被调用,Flask 可以通过Blueprint来组织URL以及处理请求。
2:蓝图作用
让应用实现模块化
3:使用步骤
1,创建一个蓝图对象
2,在这个蓝图对象上进行操作,注册路由
3,在应用对象上注册这个蓝图对象
4:通过蓝图实现学生信息的增、删、改、查
4.1 学生列表页面
# 程序初始化 from flask import Flask # 创建一个app对象 def create_app(): app = Flask(__name__,template_folder="../templates") return app
{% extends "index.html" %} {% block content %} <h2>学生列表</h2> <table border="3xp"> <thead> <tr> <td>ID</td> <td>name</td> <td>age</td> <td>gender</td> <td>options</td> </tr> </thead> <tbody> {% for foo in student %} <tr> <td>{{ foo.id }}</td> <td>{{ foo["name"] }}</td> <td>{{ foo.get("age") }}</td> <td>{{ foo.gender }}</td> <td><a href="/s_update/{{ foo.id }}">修改</a> | <a href="/s_del?id={{ foo.id }}">删除</a></td> </tr> {% endfor %} </tbody> </table> {% endblock %}
from flask import Blueprint from flask import render_template from StudentManage_BluePrint.student_data import STUDENT # 每个蓝图都可以为自己独立出一套template模板文件夹,如果不写则共享项目目录中的templates sv = Blueprint("sv", __name__, template_folder="templates") @sv.route("/s_view") def studentView(): # 学生列表 蓝图 return render_template("s_view.html", student=STUDENT)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>欢迎来到学生管理系统</h1> {% block content %} {% endblock %} </body> </html>
from StudentManage_BluePrint.student import create_app from StudentManage_BluePrint.student_view import s_view from flask import Flask app = create_app() #把学生列表蓝图,注册过来 app.register_blueprint(s_view.sv) app.run(debug=True)
# 学生数据 STUDENT = [ {'id': 1, 'name': '张三', 'age': 33, 'gender': '保密'}, {'id': 2, 'name': '李四', 'age': 44, 'gender': '男'}, {'id': 3, 'name': '王五', 'age': 55, 'gender': '女'} ]
4.2 学生增删改操作
由于增加和修改页面相似,我们统一做在一个页面中
# 程序初始化 from flask import Flask from StudentManage_BluePrint.student_view import s_view from StudentManage_BluePrint.student_oper import s_add_modify_del # 创建一个app对象 def create_app(): app = Flask(__name__,template_folder="../templates") # 把学生列表蓝图,注册过来 app.register_blueprint(s_view.sv) app.register_blueprint(s_add_modify_del.sa) return app
{% extends "index.html" %} {% block content %} <h2>学生{{ curTitle }}</h2> <form action="{{ curAction }}" method="post"> <p style="display: none">ID:<input id="stuID" name="stuID" value="{{ stu.id }}"></p> <p>姓名:<input id="stuName" name="stuName" value="{{ stu.name }}"></p> <p>年龄:<input id="stuAge" name="stuAge" value="{{ stu.age }}"></p> <p>性别:<input id="stuGender" name="stuGender" value="{{ stu.gender }}"></p> <input type="submit" value="提交"> </form> {% endblock %}
from flask import Blueprint from flask import render_template, request, redirect from StudentManage_BluePrint.student_data import STUDENT # 每个蓝图都可以为自己独立出一套template模板文件夹,如果不写则共享项目目录中的templates sa = Blueprint("sa", __name__, template_folder="templates") @sa.route("/s_add", methods=('GET', 'POST')) def studentAdd(): if request.method == "GET": return render_template("s_add_modify.html", curTitle="新增", curAction="/s_add", stu=None) else: studentID = 0 # 把拿到的数据转换成对象,添加到数据集合中 if STUDENT: maxStu = STUDENT[-1] studentID = int(maxStu["id"]) + 1 stu_dic = { "id": studentID, "name": request.form.get("stuName"), "age": request.form.get("stuAge"), "gender": request.form.get("stuGender"), } STUDENT.append(stu_dic) return redirect("/s_view") @sa.route("/s_update/<int:id>", methods=('GET', 'POST')) def studentUpdate(id): if request.method == "GET": curStu = None for stu in STUDENT: if stu['id'] == id: curStu = stu return render_template("s_add_modify.html", curTitle="编辑", curAction="/s_update/" + str(id), stu=curStu) else: # 把拿到的数据转换成对象,添加到数据集合中 for stu in STUDENT: if stu['id'] == id: stu["name"] = request.form.get("stuName") stu["age"] = request.form.get("stuAge") stu["gender"] = request.form.get("stuGender") return redirect("/s_view") @sa.route("/s_del", methods=('GET', 'POST')) def studentDel(): id = request.args.get("id") if id: for stu in STUDENT: if str(stu['id']) == str(id): print("删除元素") STUDENT.remove(stu) return redirect("/s_view")
十、特殊装饰器
1:特殊装饰器
在此之前的jinja2语言中有两个全局的装饰器
@app.template_global()
@app.template_filter()
接下来,再介绍几个
@app.before_request:请求进入视图函数之前
@app.after_request:结束视图函数之后,返回客户端之前
@app.errorhandler(404) 重定义页面 这个可以参数是常见的http状态码
2:装饰器小练习
from flask import Flask,redirect,request app=Flask(__name__) @app.route('/zsqindex') def index(): return "Hello,World!" @app.before_request def bf1(): print("bf1") @app.before_request def bf2(): print("bf2") @app.before_request def bf3(): print("bf3") @app.after_request def af1(arg): print("af1") return arg @app.after_request def af2(arg): print("af2") return arg @app.after_request def af3(arg): print("af3") return arg app.run(debug=True)
bf1
bf2
bf3
af3
af2
af1
结论
1:正常:be1 - be2 - be3 - af3 - af2 - af1
2:@app.after_request 必须得有参数和返回结果
3:通过@app.before_request来实现完善学生管理的权限校验
3.1 添加登录功能,并记录session
{% extends "index.html" %} {% block content %} <h2>学生登录</h2> <form action="/s_login" method="post"> <p>用户名:<input id="username" name="username"></p> <p>密码:<input type="password" id="pwd" name="password"></p> <input type="submit" value="提交"> {{ errormsg }} </form> {% endblock %}
from flask import Blueprint from flask import render_template, request, session, redirect from StudentManage_BluePrint.student_data import STUDENT # 每个蓝图都可以为自己独立出一套template模板文件夹,如果不写则共享项目目录中的templates sl = Blueprint("sl", __name__, template_folder="templates") @sl.route("/s_login", methods=("GET", "POSt")) def userLogin(): if request.method == "GET": return render_template("s_login.html", errormsg="") username = request.form.get("username") password = request.form.get("password") for stu in STUDENT: if stu["name"] == username and stu["password"] == password: session["user"] = stu return redirect("/s_view") else: session["user"] = None return render_template("s_login.html", errormsg="用户不存在或密码错误!")
3.2 修改__init__文件,将登录蓝图信息注册
# 程序初始化 from flask import Flask,session from StudentManage_BluePrint.student_view import s_view from StudentManage_BluePrint.student_oper import s_add_modify_del from StudentManage_BluePrint.UserLogin import s_login # 创建一个app对象 def create_app(): app = Flask(__name__,template_folder="../templates") # 把学生列表蓝图,注册过来 app.register_blueprint(s_view.sv) app.register_blueprint(s_add_modify_del.sa) app.register_blueprint(s_login.sl) app.secret_key="Hello,Flask" return app if __name__ == '__main__': app = create_app()
3.3 修改manage.py 方法,通过@app.before_request进行权限判断
from StudentManage_BluePrint.student import create_app,session from flask import Flask,request app = create_app() @app.before_request def islogin(): if request.path == "/s_login": return None if not session.get("user"): return "您尚未登录,请先登录!!" app.run(debug=True)
3.4 在数据源结构中添加password字段
# 学生数据 STUDENT = [ {'id': 1, 'password': '3', 'name': '张三', 'age': 33, 'gender': '保密'}, {'id': 2, 'password': '4', 'name': '李四', 'age': 44, 'gender': '男'}, {'id': 3, 'password': '5', 'name': '王五', 'age': 55, 'gender': '女'} ]
十一、CBV
1:什么是CBV
类通用视图:class base views 与之相对应的就是我们前面经常使用的 函数通用视图 function base views
from flask import Flask, render_template # 1:导入包views from flask import views app = Flask(__name__) # 2:创建类 class CBVClass(views.MethodView): def get(self): return render_template("/cbv.html") def post(self): return "我是post" # 3:设置关系 app.add_url_rule("/CBV", endpoint=None, view_func=CBVClass.as_view("cbv")) app.run(debug=True) ''' (1)导入views模块: from flask import views (2)定义类,继承views.MethodView类: class 类名(views.MethodView) (3)在类中定义函数名为允许的请求方式的小写形式,进行函数定义,如def get(self):... (4)添加路由规则: CBV:app.add_url_rule(rule,endpoint='',view_func=类名.as_view(name='')) FBV:app.add_url_rule(rule,endpoint='',view_func=函数名))(直接替代@app.route()方式) 参数: rule 请求路径 endpoint设置mapping路由映射函数rule:{endpoint:func} view_func路由映射的视图函数或者类(as_view()中的name参数设置当前路由映射函数名,唯一指定,不设置endpoint自动为name值) (5)methods=[]类中设置属性,添加允许的请求方式,不写默认都支持 (6)decorators = []对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,以此执行 '''
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/CBV" method="post"> <input type="submit" value="提交"> </form> </body> </html>
2:总结:
(1)导入views模块: from flask import views
(2)定义类,继承views.MethodView类: class 类名(views.MethodView)
(3)在类中定义函数名为允许的请求方式的小写形式,进行函数定义,如def get(self):...
(4)添加路由规则:
CBV:app.add_url_rule(rule,endpoint='',view_func=类名.as_view(name=''))
FBV:app.add_url_rule(rule,endpoint='',view_func=函数名))(直接替代@app.route()方式)
参数:
rule 请求路径
endpoint设置mapping路由映射函数rule:{endpoint:func}
view_func路由映射的视图函数或者类(as_view()中的name参数设置当前路由映射函数名,唯一指定,不设置endpoint自动为name值)
(5)methods=[]类中设置属性,添加允许的请求方式,不写默认都支持
(6)decorators = []对类中的函数都加上装饰器,列表中可以放多个装饰器函数名,以此执行
十二、flash
1:flash例子
from flask import Flask, render_template # 1:导入flash,get_flashed_messages from flask import flash, get_flashed_messages app = Flask(__name__) # 2:设置secret_key app.secret_key = "hello,Flash" @app.route("/setFlash") def setflash(): flash("Hello,Flash!", "sayHi") return "flash添加成功" @app.route("/getFlash1") def getflash1(): return str(get_flashed_messages("sayHi")) @app.route("/getFlash2") def getflash2(): return str(get_flashed_messages("sayHi")) app.run(debug=True)