1.Flask: from flask import Flask app = Flask(__name__) # 从源码中能够看出,Flask集成的run方法是由werkzeug中的run_simple方法提供的。 app.run() # run_simple(host,port,obj_or_func()) obj() 对象加括号至关于调用 __call__() 方法 2.简单路由 @app.route("/index",methods=["GET","POST"]) def index(){ return } 默认GET请求,若是改写了methods,GET必定要加上 3.flask 中的返回值: 左边是django,右边是flask HttpResponse == return "OK!" render == render_template redirect == redirect return send_file() # 将一个文件打开,而后返回文件内容 4.request: request form:POST中的FormData数据存放在form(字典) 经过字典的方式去取值 args:URL参数存放在args(字典) 经过字典的方式去取值 values: url + FormData .to_dict()同名key url覆盖Formdata data: 当 content-type:None 也就是没法处理时,将数据存放在data中 而且以b"{k:v}"形式存储,是bytes类型 json: 当 content-type:application/json 数据以Json放存放 5.Flask Jinja2 {{}} 非逻辑 {%%} 包含逻辑 {% for i in a %} {% endfor %} {% if True %} {% endif %} 前端:| safe :安全标签字符串儿 后端: Markup(tag) :安全标签字符串儿 @app.template_global() # 定义模板全局函数 def func(): return 1+1 前端: {{ func() }} @app.template_filter() # 定义模板全局函数,相似偏函数 def func(a): return a 前端: {{ 1 | func() }} extends 模板继承 include 加载模板 宏定义:不多用 {% macro func(ty , na) %} <input type="{{ ty }}" name="{{ na }}" > {% endmacro %} 调用: func("text","username") 6.flask 中的 session app.secret_key = "alex DSB" session 序列化一个加密字符串,存在前端的cookie。它的键名就是session 当发起请求的时候,将字符串发送到后端反序列化,拿出存放在服务器端的session session["key"] = "value" # 就是字典 注意:cookie存储在浏览器中,session存储在服务器中。 cookie至关于钥匙,session至关于银行保险柜!
昨天的做业就是,有3个视图函数,分别是/login,/student_list,/student_detail。写一个装饰器,除了/login之外,其余视图函数都要登陆才行!css
使用session判断!html
原始代码前端
from flask import Flask,render_template,sessions,request,redirect app = Flask(__name__) USER = {'username': 'xiao', 'password': "123"} @app.route("/login",methods=["POST","GET"]) def login(): if request.method == "GET": # 前端模板中使用了msg,这里就算是传递空,也要出现msg return render_template("login.html", msg="") if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]: return redirect("/student_list") return render_template("login.html", msg="用户名密码错误") @app.route("/student_list") def student_list(): return "学生列表" @app.route("/student_detail") def student_detail(): return "学生详情" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
使用装饰器mysql
from flask import Flask,render_template,session,request,redirect app = Flask(__name__) # 使用session,必须设置secret_key app.secret_key = "123asdzxc" USER = {'username': 'xiao', 'password': "123"} def auth(func): def inner(*args,**kwargs): if session.get("user"): return func(*args,**kwargs) else: return redirect("/login") return inner @app.route("/login",methods=["POST","GET"]) def login(): if request.method == "GET": # 前端模板中使用了msg,这里就算是传递空,也要出现msg return render_template("login.html", msg="") username = request.form["username"] # 获取POST请求时,FormData中的参数 # password = request.form.get("password") if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]: # 设置session session["user"] = username return redirect("/student_list") return render_template("login.html", msg="用户名密码错误") @app.route("/student_list",endpoint="student_list") @auth def student_list(): return "学生列表" @app.route("/student_detail",endpoint="student_detail") @auth def student_detail(): return "学生详情" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
重启flask,直接访问student_listweb
http://127.0.0.1:5000/student_list
打开浏览器工具,查看网络。它会跳转至登陆页面!sql
输入正确的用户名和密码数据库
提交以后,跳转页面django
注意:使用装饰器的视图函数,必需要定义endpoint参数。json
由于使用装饰器以后,视图函数都是inner,因此flask没法区分,路由到底指向哪个视图函数。flask
启动flask以后,会直接报错。endpoint参数,是给url起别名,惟一标识。能够作url反向解析!
还有一种方法,使用@functools.wraps装饰器,保留原函数信息,好比函数名。
可是不推荐使用。由于定义视图函数,自己就应该定义endpoint参数
Flask中的路由系统其实咱们并不陌生了,从一开始到如今都一直在应用
@app.route("/",methods=["GET","POST"])
为何要这么用?其中的工做原理咱们知道多少?
1. @app.route() 装饰器中的参数
若是不明白装饰器 点击这里
methods : 当前 url 地址,容许访问的请求方式
from flask import Flask,request app = Flask(__name__) @app.route("/info", methods=["GET", "POST"]) def student_info(): stu_id = int(request.args["id"]) return f"hello kitty {stu_id}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
访问url,注意:要带上参数id,不然报错
http://127.0.0.1:5000/info?id=1
效果以下:
endpoint : 反向url地址,默认为视图函数名 (url_for)
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", methods=["GET", "POST"],endpoint="r_info") def student_info(): print(url_for("r_info")) # /info stu_id = int(request.args["id"]) return f"hello kitty {stu_id}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
刷新页面,效果同上!查看Pycharm控制台输出:
/info
注意:这并非完整的url。若是要给前端妹子,返回一个完整的URL怎么办呢?
url_for:用于反向生成url,也能够附带一些参数,好比想要完整的URL,能够设置_external为Ture:
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", methods=["GET", "POST"],endpoint="r_info") def student_info(): stu_id = int(request.args["id"]) print(url_for("r_info", _external=True)) return f"hello kitty {stu_id}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
刷新页面,效果同上!查看Pycharm控制台输出:
http://127.0.0.1:5000/info
可是还不够,参数没有啊?怎么办?再加上url参数。
注意:因为id是动态参数,因此后台获取时,要和实际的参数匹配。这里是id
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", methods=["GET", "POST"],endpoint="r_info") def student_info(): stu_id = int(request.args["id"]) print(url_for("r_info", _external=True,id=stu_id)) return f"hello kitty {stu_id}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
刷新页面,效果同上!查看Pycharm控制台输出:
http://127.0.0.1:5000/info?id=1
这下,就很是完美了!
defaults : 视图函数的参数默认值{"nid":100}
注意:视图函数必需要设置形参nid,不然报错!
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", methods=["GET", "POST"],endpoint="r_info",defaults={"nid": 100}) def student_info(nid): # stu_id = int(request.args["nid"]) print(url_for("r_info", _external=True)) print(nid) return f"hello kitty {nid}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
访问url: http://127.0.0.1:5000/info
效果以下:
strict_slashes : url地址结尾符"/"的控制 False : 不管结尾 "/" 是否存在都可以访问 , True : 结尾必须不能是 "/"
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", strict_slashes=True) def student_info(): return "hello kitty info" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
末尾不带 "/"
末尾带 "/"
也就是说:strict_slashes = True ,表示开启路由严格匹配模式!即便末尾多了一个"/",也不容许访问!
将参数改成False
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", strict_slashes=False) def student_info(): return "hello kitty info" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
刷新页面,又能够访问了
若是多加一个s,会报404
总结:strict_slashes 用来控制末尾是否有"/",为Ture,带 "/"不容许!
为False,无论你带不带"/",均可以访问!
redirect_to : url地址重定向
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info", redirect_to="/infos") def student_info(): return "hello kitty info" @app.route("/infos") def student_infos(): return "Hello Tom infos" if __name__ == '__main__': app.run("0.0.0.0", 5000, debug=True)
访问url: http://127.0.0.1:5000/info,会发生重定向
查看浏览器工具,查看网络。它经历了2次请求!
它有什么应用场景呢?
好比你的网站域名是xx.com,后来你的网页改版了,换了新的域名qqxx.com。可是老客户还不知道你的新域名啊!怎么办呢?用重定向就能够了!
subdomain : 子域名前缀 subdomian="qq" 这样写能够获得 qq.xx.com 前提是app.config["SERVER_NAME"] = "xx.com:5000"
from flask import Flask,request,url_for app = Flask(__name__) # 必定必定必定要写端口!!!!!! app.config["SERVER_NAME"] = "xx.com:5000" @app.route("/",endpoint="r_info",subdomain="qq") def student_info(): print(url_for("r_info", _external=True,)) return "hello kitty info" if __name__ == '__main__': # 监听端口为5000,注意:要和SERVER_NAME匹配! app.run("0.0.0.0", 5000, debug=True)
注意:app.config["SERVER_NAME"] = "xx.com:5000"。
必定要加端口!必定要加端口!必定要加端口!重要的事情说三遍!!!
就是由于没有加端口,快要放弃了!google了一把,终于找到缘由了!
这里是window 10访问。必需要修改本机的Hosts文件,至于怎么修改,为啥没有权限,请自行百度!
修改Hosts文件,添加一条记录
127.0.0.1 qq.xx.com
打开cmd窗口,ping qq.xx.com,请确保返回地址是127.0.0.1
打开浏览器访问url,注意:只能是qq.xx.com访问。不能是xx.com!访问时,必定要带上端口!
http://qq.xx.com:5000/
效果以下:
关于路由目前就说这么多,以后的课程中会有关于Flask路由系统的源码剖析,再详细说明Flask路由系统的工做原理
2.动态参数路由:
<int:nid> 就是在url后定义一个参数接收
可是这种动态参数路由,在url_for的时候,必定要将动态参数名+参数值添加进去,不然会抛出参数错误的异常
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info/<int:nid>", endpoint="r_info") def student_info(nid): print(url_for("r_info", _external=True,nid=nid)) return f"hello kitty {nid}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': # 监听端口为5000 app.run("0.0.0.0", 5000, debug=True)
访问url,必定要带上参数,并且参数必须是数字!
查看Pycharm控制台输出:
12 <class 'int'> http://127.0.0.1:5000/info/12
若是是字符串,会报错
from flask import Flask,request,url_for app = Flask(__name__) @app.route("/info/<string:nid>", endpoint="r_info") def student_info(nid): print(nid,type(nid)) print(url_for("r_info", _external=True,nid=nid)) return f"hello kitty {nid}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': # 监听端口为5000 app.run("0.0.0.0", 5000, debug=True)
刷新页面,就能够访问了
查看Pycharm控制台输出:
ask <class 'str'> http://127.0.0.1:5000/info/ask
参数是数字也是正常的
3.路由正则:
通常不用,若是有特殊需求,不怕麻烦的话,这个东西仍是挺好用的,前提是你的正则玩儿的很6
from flask import Flask,request,url_for # 导入转换器基类 from werkzeug.routing import BaseConverter app = Flask(__name__) # 自定义正则转换器 class RegexConverter(BaseConverter): def __init__(self, url_map, *args): super(RegexConverter, self).__init__(url_map) # 将接受的第1个参数看成匹配规则进行保存 self.regex = args[0] # 将自定义转换器添加到转换器字典中,并指定转换器使用时名字为: re app.url_map.converters['re'] = RegexConverter # 使用转换器去实现自定义匹配规则 # 当前此处定义的规则是:3位数字 @app.route('/info/<re("[0-9]{3}"):nid>', endpoint="r_info") def student_info(nid): print(url_for("r_info", _external=True,nid=nid)) return f"nid 为 {nid}" # Python3.6的新特性 f"{变量名}" if __name__ == '__main__': # 监听端口为5000 app.run("0.0.0.0", 5000, debug=True)
访问url,注意:参数必须是3位数字
本文参考:
http://www.javashuo.com/article/p-efehdfyj-mx.html
Flask 是一个很是灵活且短小精干的web框架 , 那么灵活性从什么地方体现呢?
有一个神奇的东西叫 Flask配置 , 这个东西怎么用呢? 它能给咱们带来怎么样的方便呢?
首先展现一下:
from flask import Flask app = Flask(__name__) # type:Flask app.config["DEBUG"] = True if __name__ == '__main__': app.run()
这句 app.config["DEBUG"] = True 能够实现的功能可刺激了
代码只要发生改动,自动重启Flask程序(app.run)
在控制台打印的信息很是全面
以上两个功能就是传说中的 DEBUG 模式(调试模式)
Flask的配置就是在 app.config 中添加一个键值对,可是你存进去的键必须是config中应该存在的,若是再也不存在的话,它会默认无用,就这么放着
config中有多少有用的key 呢?
{ '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, }
以上这些Key,均可以被改写,固然他们也都是有默认值存在的,若是没有特殊状况,不要改写它的默认值
修改配置的方式大约是两种
1.直接对app.config进行修改
app.config["DEBUG"] = True
2.使用类的方式导入
首先要有一个settings.py的文件
class FlaskSetting(object): DEBUG = True
而后咱们在Flask的启动文件中就能够这么写
from flask import Flask # 导入自定义配置文件的配置类 from settings import FlaskSetting app = Flask(__name__) # 应用配置类 app.config.from_object(FlaskSetting) if __name__ == '__main__': app.run()
这叫作类导入配置
这是针对一个已经实例化的app进行的配置
那么在Flask实例化的时候,传递的参数是什么鬼呢?
其实能够理解为对Flask实例进行的初始配置,这里面的参数是很是好理解,注意关键字是很是很是很是好理解
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录 static_host = None, # 远程静态文件所用的Host地址,默认为空 static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用 # host_matching是否开启host主机位匹配,是要与static_host一块儿使用,若是配置了static_host, 则必须赋值为True # 这里要说明一下,@app.route("/",host="localhost:5000") 就必需要这样写 # host="localhost:5000" 若是主机头不是 localhost:5000 则没法经过当前的路由 host_matching = False, # 若是不是特别须要的话,慎用,不然全部的route 都须要host=""的参数 subdomain_matching = False, # 理论上来讲是用来限制SERVER_NAME子域名的,可是目前尚未感受出来区别在哪里 template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录 instance_path = None, # 指向另外一个Flask实例的路径 instance_relative_config = False # 是否加载另外一个实例的配置 root_path = None # 主模块所在的目录的绝对路径,默认项目目录
这里面,咱们经常使用的参数有
static_folder = 'static', # 静态文件目录的路径 默认当前项目中的static目录 static_url_path = None, # 静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用 template_folder = 'templates' # template模板目录, 默认当前项目中的 templates 目录
记住这些就行了,通常的项目中,只修改这些参数
昨天已经讲到了template_folder,它是用来指定模板目录的,默认是templates
注意:若是设置template_folder = 'templates',这里面的templates它是相对路径!
假设py文件和templates不在同一目录下,好比这样:
./
├── bin
│ └── start.py
└── templates
└── home.html
那么start.py使用模板时,应该这么设置 template_folder = '../templates'
完整代码以下:
from flask import Flask,render_template app = Flask(__name__,template_folder="../templates") @app.route("/") def index(): return render_template("home.html") if __name__ == '__main__': app.run()
若是找不到模板文件,会提示
静态文件目录的路径 默认当前项目中的static目录
目录结构以下:
./
├── bin
│ └── start.py
├── static
│ └── meizi.jpg
└── templates
└── home.html
start.py
from flask import Flask,render_template app = Flask(__name__,template_folder="../templates",static_folder="../static") @app.route("/") def index(): return render_template("home.html") if __name__ == '__main__': app.run()
home.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>古装美女</h3> <img src="/static/meizi.jpg" alt=""> </body> </html>
meizi.jpg 这是一个妹子图片,本身百度搜索一下
重启flask程序,效果以下:
查看网络,图片的实际路径是:
http://127.0.0.1:5000/static/meizi.jpg
静态文件目录的url路径 默认不写是与static_folder同名,远程静态文件时复用
怎么知道static_url_path和static_folder默认同名呢?
修改start.py,打印变量
from flask import Flask,render_template app = Flask(__name__,template_folder="../templates",static_folder="../static") @app.route("/") def index(): print(app.static_folder) print(app.static_url_path) return render_template("home.html") if __name__ == '__main__': app.run()
刷新页面,查看Pycharm控制台输出:
/static
/static
这2个确实是同样的!
static_url_path变量是能够修改的,可是和前端保持一致
修改start.py
from flask import Flask,render_template app = Flask(__name__,template_folder="../templates",static_folder="../static",static_url_path="/app") @app.route("/") def index(): print(app.static_folder) print(app.static_url_path) return render_template("home.html") if __name__ == '__main__': app.run()
修改home.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>古装美女</h3> <img src="/app/meizi.jpg" alt=""> </body> </html>
重启flask,刷新页面,效果同上!
注意:若是使用蓝图,并作了代码拆分。静态目录名不能是static,模板目录不能是templates。必须更名!!!
必须指定3个参数
template_folder="../templates",static_folder="../statics",static_url_path="/statics"
不然会出现,模板没法渲染。css访问出现404的问题!
视图渲染时,使用
return render_template("index.html")
模板引用css时,使用
<link rel="stylesheet" href="/statics/bootstrap.min.css">
本文参考:
http://www.javashuo.com/article/p-qdsnjfmg-cd.html
Flask中提供了蓝图,专门用做Flask的模块化。对于蓝图,能够看官方介绍,这里翻译过来的:
Flask使用蓝图的概念来制做应用程序组件和支持应用程序内部或跨应用程序的通用模式。蓝图能够大大简化大型应用程序的工做方式,并为Flask扩展提供了在应用程序上注册操做的中心手段。Blueprint对象的工做方式与Flask应用程序对象相似,但实际上它不是一个应用程序。相反,它是如何构造或扩展应用程序的蓝图。
总之,蓝图可使咱们的程序更加模块化,不一样功能的路由能够放在不一样的模块下,最后集中到启动类中
蓝图,听起来就是一个很宏伟的东西
在Flask中的蓝图 blueprint 也是很是宏伟的
它的做用就是将 功能 与 主服务 分开怎么理解呢?
好比说,你有一个客户管理系统,最开始的时候,只有一个查看客户列表的功能,后来你又加入了一个添加客户的功能(add_user)模块, 而后又加入了一个删除客户的功能(del_user)模块,而后又加入了一个修改客户的功能(up_user)模块,在这个系统中,就能够将
查看客户,修改客户,添加客户,删除客户的四个功能作成蓝图加入到客户管理系统中,本篇最后会作一个这样的例子,可是首先咱们要搞清楚什么是蓝图 blueprint
1.初识Flask蓝图(blueprint)
建立一个项目而后将目录结构作成:
./
├── manager.py
└── student_view
└── s_view.py
注意:要手动建立目录student_view,并在此目录下建立s_view.py
s_view.py
from flask import Blueprint # 导入 Flask 中的蓝图 Blueprint 模块 sv = Blueprint("sv", __name__) # 实例化一个蓝图(Blueprint)对象 @sv.route("/svlist") # 这里添加路由和视图函数的时候与在Flask对象中添加是同样的 def view_list(): return "svlist_view_list"
manager.py
from flask import Flask # 导入此前写好的蓝图模块 from student_view import s_view app = Flask(__name__) # type:Flask # 在Flask对象中注册蓝图模块中的蓝图对象 s_view 中的 sv app.register_blueprint(s_view.sv) if __name__ == '__main__': app.run("0.0.0.0",5000) # 如今Flask对象中并无写任何的路由和视图函数
开启服务,而后访问 http://127.0.0.1:5000/svlist 查看结果
很明显,咱们没有在Flask对象中添加路由,可是咱们注册了有路由和视图函数的sv蓝图对象
2.如何理解蓝图呢?
其实咱们能够理解成一个没有run方法的Flask对象,这个理论虽然有不少的漏洞,可是对于刚接触蓝图的你来讲,就这么样理解,没有错
下面来看一下,在实例化蓝图的时候能够传递的参数都有什么,你就能彻底理解了
目录结构:
./
├── manager.py
├── student_view
│ └── s_view.py
├── sv_static
│ └── meizi.jpg
└── sv_template
└── svlist.html
s_view.py
from flask import Blueprint # 导入 Flask 中的蓝图 Blueprint 模块 from flask import render_template sv = Blueprint("sv", __name__, # 这里是相对路径,要加../ template_folder="../sv_template", # 每一个蓝图均可觉得本身独立出一套template模板文件夹,若是不写则共享项目目录中的templates static_folder="../sv_static" # 静态文件目录也是能够独立出来的 ) # 实例化一个蓝图(Blueprint)对象 @sv.route("/svlist") def view_list(): return render_template("svlist.html")
svlist.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>Hello ! I am sv_template</p> <img src="/sv_static/meizi.jpg"> </body> </html>
manager.py的代码,不须要改动。
重启flask,刷新页面:
妹子,仍是那个妹子
从这个例子中咱们总结出:
Blueprint 其实能够理解为一个了没有run方法的 Flask 对象
只要Blueprint被 Flask 注册了,就必定会生效
坑来了!坑来了!
蓝图内部的视图函数及route不要出现重复,不然~大家本身试试吧
3.使用蓝图,作一个增删改查用户
要有一个文件存放咱们的原始数据
student_data.py 文件中的内容:
STUDENT = [ {'id':1,'name': '韩雪', 'age': 24, 'gender': '女'}, {'id':2,'name': '舒畅', 'age': 23, 'gender': '女'}, {'id':3,'name': '唐嫣', 'age': 25, 'gender': '女'} ]
而后咱们根据以上内容进行增删改查
3.1 使用蓝图进行web应用搭建:
目录结构以下:
./ ├── manager.py ├── student │ └── __init__.py └── student_data.py
__init__.py 文件中的内容:
from flask import Flask def create_app(): app = Flask(__name__) return app
这个文件咱们会修改函数 create_app中的代码
manager.py 文件中的内容
from student import create_app flask_app = create_app() if __name__ == '__main__': flask_app.run("0.0.0.0",5000,debug=True)
经过这种方式启动 Flask 程序
3.2 使用Flask蓝图,查看学生信息
项目结构以下:
./ ├── html │ └── s_list.html ├── manager.py ├── student │ └── __init__.py ├── student_data.py └── student_select └── stu_select.py
s_list.html 文件中的内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>学生列表</title> </head> <body> <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> <a href="/s_add"> 添加学生 </a> </body> </html>
stu_select.py 文件中的内容:
from flask import Blueprint from flask import render_template from student_data import STUDENT ss_blueprint = Blueprint("ss_b", __name__, template_folder="../html") @ss_blueprint.route("/s_list") def s_list(): return render_template("s_list.html", student=STUDENT)
student/__init__.py 文件中的内容:
from flask import Flask from student_select import stu_select def create_app(): app = Flask(__name__) app.register_blueprint(stu_select.ss_blueprint) return app
赶忙运行一下manager.py 来访问一下,咱们的成果
什么连接都不要点,由于点啥都很差使,以后我们一个一个的作
3.3. 使用Flask蓝图,添加一个学生
增长一个目录,结构以下:
./ ├── html │ ├── s_add.html │ └── s_list.html ├── manager.py ├── student │ └── __init__.py ├── student_add │ └── stu_add.py ├── student_data.py └── student_select └── stu_select.py
s_add.html 文件中的内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>学生列表</title> </head> <body> <form method="post"> ID:<input type="text" name="id"> <br> 姓名:<input type="text" name="name"><br> 年龄:<input type="text" name="age"><br> 性别:<input type="text" name="gender"><br> <input type="submit" value="添加学生"> </form> </body> </html>
stu_add.py 文件中的内容
from flask import Blueprint from flask import redirect from flask import request from flask import render_template from student_data import STUDENT s_add = Blueprint("s_add", __name__, template_folder="html", static_folder="static") # type:Blueprint @s_add.route("/s_add", methods=["GET", "POST"]) def s_add_view(): if request.method == "POST": stu_dic = { "id": request.form["id"], "name": request.form["name"], "age": request.form["age"], "gender": request.form["gender"] } STUDENT.append(stu_dic) return redirect("/s_list") return render_template("s_add.html")
这里面咱们让他添加完一个学生,就返回到s_list查看学生列表
student/__init__.py 文件中的内容
from flask import Flask from student_select import stu_select from student_add import stu_add def create_app(): app = Flask(__name__) app.register_blueprint(stu_select.ss_blueprint) app.register_blueprint(stu_add.s_add) return app
重启flask服务,点击添加学生
若是你要是从新启动服务了,那么你刚刚添加的学生信息就没有了
添加完成以后
添加学生的Blueprint已经作完了
3.4. 使用Flask蓝图,修改学生信息
增长一个目录,结构以下:
./ ├── html │ ├── s_add.html │ ├── s_list.html │ └── s_update.html ├── manager.py ├── student │ └── __init__.py ├── student_add │ └── stu_add.py ├── student_data.py ├── student_select │ └── stu_select.py └── student_update └── stu_update.py
s_update.html 文件中的内容:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>学生列表</title> </head> <body> <form method="post"> <input type="text" name="id" hidden value="{{ student.id }}"><br> 姓名:<input type="text" name="name" value="{{ student.name }}"><br> 年龄:<input type="text" name="age" value="{{ student.age }}"><br> 性别:<input type="text" name="gender" value="{{ student.gender }}"><br> <input type="submit" value="修改信息"> </form> </body> </html>
stu_update.py 文件中的内容:
from flask import Blueprint from flask import render_template from flask import redirect from flask import request from student_data import STUDENT s_update = Blueprint("s_update", __name__, template_folder="html", static_folder="static") @s_update.route("/s_update/<int:nid>",methods=["GET","POST"]) def s_update_view(nid): if request.method == "POST": stu_id = int(request.form["id"]) stu_dic = { "id": stu_id, "name": request.form["name"], "age": request.form["age"], "gender": request.form["gender"] } for index,stu in enumerate(STUDENT): if stu["id"] == stu_id: STUDENT[index] = stu_dic return redirect("/s_list") for stu in STUDENT: if stu["id"] == nid : return render_template("s_update.html", student=stu) return render_template("s_update.html", student="")
student/__init__.py 文件中的内容:
from flask import Flask from student_select import stu_select from student_add import stu_add from student_update import stu_update def create_app(): app = Flask(__name__) # type:Flask app.register_blueprint(stu_select.ss_blueprint) app.register_blueprint(stu_add.s_add) app.register_blueprint(stu_update.s_update) return app
重启flask,刷新网页。点击一条记录,并修改
修改年龄
点击修改信息,效果以下:
修改的功能也已经作完了,删除功能也是同样的。
3.4. 使用Flask蓝图,删除学生信息
增长一个目录,结构以下:
./ ├── html │ ├── s_add.html │ ├── s_list.html │ └── s_update.html ├── manager.py ├── student │ └── __init__.py ├── student_add │ └── stu_add.py ├── student_data.py ├── student_delete │ └── stu_delete.py ├── student_select │ └── stu_select.py └── student_update └── stu_update.py
注意:删除不须要html文件
修改s_list.html,这里的删除连接有问题
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>学生列表</title> </head> <body> <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_delete/{{ foo.id }}">删除</a></td> </tr> {% endfor %} </tbody> </table> <a href="/s_add"> 添加学生 </a> </body> </html>
stu_delete.py 文件中的内容:
from flask import Blueprint from flask import render_template from flask import redirect from flask import request from student_data import STUDENT s_delete = Blueprint("s_delete", __name__, template_folder="html", static_folder="static") @s_delete.route("/s_delete/<int:nid>",methods=["GET","POST"]) def s_delete_view(nid): for stu in STUDENT: if stu["id"] == nid : STUDENT.remove(stu) # 列表移除key return redirect("/s_list") return redirect("/s_list")
student/__init__.py 文件中的内容,注册蓝图
from flask import Flask from student_select import stu_select from student_add import stu_add from student_update import stu_update from student_delete import stu_delete def create_app(): app = Flask(__name__) app.register_blueprint(stu_select.ss_blueprint) app.register_blueprint(stu_add.s_add) app.register_blueprint(stu_update.s_update) app.register_blueprint(stu_delete.s_delete) return app
重启flask,测试效果:
增删改查,功能所有完结了!各位看官,有时间的话,可使用pymysql实现!
建表以及插入数据
# 建立数据库 CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(32) DEFAULT NULL COMMENT '用户名', `age` int(11) DEFAULT NULL COMMENT '年龄', `gender` enum('女','男') DEFAULT '女' COMMENT '性别', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; # 插入3条数据 INSERT INTO `student` (`id`, `name`, `age`, `gender`) VALUES ('1', '韩雪', '24', '女'); INSERT INTO `student` (`id`, `name`, `age`, `gender`) VALUES ('2', '舒畅', '23', '女'); INSERT INTO `student` (`id`, `name`, `age`, `gender`) VALUES ('3', '唐嫣', '25', '女');
完整代码,请参考:
连接:https://pan.baidu.com/s/1wOOM2xk6YDZRo5HljgszpQ 密码:viel
本文参考:
http://www.javashuo.com/article/p-ahcaxosm-kq.html
Flask咱们已经学习不少基础知识了,如今有一个问题
咱们如今有一个 Flask 程序其中有3个路由和视图函数,以下:
from flask import Flask app = Flask(__name__) @app.route("/login") def login(): return "Login" @app.route("/index") def index(): return "Index" @app.route("/home") def home(): return "Home" if __name__ == '__main__': app.run("0.0.0.0", 5000)
启动flask,访问home页面
如今要求是,若是登录了,就能够访问 index 和 home 页面,若是没登陆就跳转到 login 登陆
要怎么解决呢, session 对, 用 session 除了 Login 函数以外的全部函数里面全校验 session 是否登陆了
太麻烦了,如今我们只有3个函数,若是成百上千个怎么整啊
装饰器,对没错,装饰器是一个很好的方案,可是啊,我如今仍是成败上千个函数,我要在每个函数定义的时候加上@装饰器,仍是很麻烦
那么就引出了咱们要学习的第一个知识点:
from flask import Flask,request,redirect,session app = Flask(__name__) app.secret_key = "DragonFire" @app.before_request def is_login(): # 判断是否登陆 # 白名单设置,判断为登陆页面时 if request.path == "/login": # 跳过处理 return None # 判断session是不存在时 if not session.get("user"): # 重定向到登陆页面 return redirect("/login") @app.route("/login") def login(): return "Login" @app.route("/index") def index(): return "Index" @app.route("/home") def home(): return "Home" if __name__ == '__main__': app.run("0.0.0.0", 5000)
@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数以前执行
request.path 是来读取当前的url地址若是是 /login 就容许直接经过 return None 你能够理解成经过放行
校验session中是否有user 若是没有的话,证实没有登陆,因此绝不留情的 redirect("/login") 跳转登陆页面
还有一个要提的 @app.before_first_request 它与 @app.before_request 极为类似或者说是如出一辙,只不过它只会被执行一次
@app.before_request修饰器在开发中用处很是大,好比判断某个ip是否有恶意访问行为,从而进行拦截等操做
重启flask,再次访问home页面,效果以下:
打开浏览器工具,查看网络
2. @app.after_request 在响应(response)以前作出响应
from flask import Flask,request,redirect,session app = Flask(__name__) app.secret_key = "DragonFire" @app.before_request def is_login(): # 判断是否登陆 # 白名单设置,判断为登陆页面时 if request.path == "/login": # 跳过处理 return None # 判断session是不存在时 if not session.get("user"): # 重定向到登陆页面 return redirect("/login") @app.after_request def foot_log(environ): # 记录访问日志 print(environ) # 响应信息 # 判断请求路径不是登陆页面 if request.path != "/login": # 打印访问路径 print("有客人访问了",request.path) return environ @app.route("/login",methods=["POST","GET"]) def login(): if request.method == "GET": return "Login" user = request.form["username"] # form表单获取 pwd = request.form["password"] # form表单获取 # 判断form表示数据和 后台数据库匹配 # models.UserInfo.objects.filter(username=user,password=pwd).first() if user == 'xiao' and pwd == '123': # 设置session session["user"] = user # 跳转首页 return redirect("/index") @app.route("/index") def index(): return "Index" @app.route("/home") def home(): return "Home" if __name__ == '__main__': app.run("0.0.0.0", 5000)
@app.after_request修饰器是在用户请求获得函数响应后被执行,不过须要注意的是这个执行是在函数返回数据前被调用,即请求已经被app.route修饰的函数响应过了,已经造成了response,但还未返回给用户的时候,调用的。
它能够作访问统计,不多应用,可是要了解有这么个东西
重启flask,访问home页面,效果同上!它仍是会跳转到登陆页面
查看Pycharm控制台输出:
<Response 219 bytes [302 FOUND]>
有客人访问了 /home
使用postman发送post请求
点击发送,查看返回结果
从上图能够看出,验证经过了!跳转到首页
可能有人会有疑问,咦?@app.before_request不是装饰器吗?为何没有在home视图函数中应用,却生效了呢?
应该这样才对啊
@app.route("/home") @app.before_request def home(): return "Home"
NoNoNo!@app.before_request是一个全局装饰器,它是针对全部视图函数的。只要定义了@app.before_request,那么每个视图函数都会应用。同理,@app.after_request也是全局装饰器!
你能够把@app.before_request理解为django的中间件,请求到达视图函数以前,先走中间件!
若是仍是不明白,看下面的流程图
解释:
is_login()函数被@app.before_request修饰之后,每一次请求到来后,都会先进入函数is_login()中,如上代码,获取请求的路径以及session。若是是登陆页面,不处理。若是session中user不存在,跳转到登陆页面。当session中user存在时,请求才会正常进入到app.route修饰的函数中响应,若是有多个函数被@app.before_request修饰了,那么这些函数会被依次执行。
好比这样:
@app.before_request def malicious_ip(): # 判断恶意IP pass @app.before_request def xss(): # 判断xss攻击 pass @app.before_request def is_login(): # 判断登陆 pass
@app.before_request修饰器在开发中用处很是大,好比判断某个ip是否有恶意访问行为,从而进行拦截等操做。
此外同理,app.after_request修饰器是在用户请求获得函数响应后被执行,不过须要注意的是这个执行是在函数返回数据前被调用,即请求已经被app.route修饰的函数响应过了,已经造成了response,但还未返回给用户的时候,调用的。
本文参考:
http://www.javashuo.com/article/p-pruhuxdw-dh.html
今日总结:
1.flask路由 endpoint 反向url标签 url_for 经过endpoint反向生成url methods=[] 容许进入视图函数的请求方式,默认GET strict_slashes 是否严格要求URL地址 /login/ /login redirect_to 跳转地址,重定向地址 动态URL参数 /index/1 /index/<int:id> def index(id) 2.Flask实例化配置 template_folder 指定模板路径 static_folder 指定静态文件路径 static_url_path 静态文件路径访问url 3.app对象配置: app.config.from_object(Class) DEBUG # 开启代码调试模式(开发) SECRET_KEY # 用到session时必须添加 4.蓝图: Blueprint 至关因而一个不可以被run的flask对象 Blueprint("blue",__name__,template_folder,static_folder,static_url_path) 能够为蓝图增长独立的模板和静态目录 为蓝图增长路由 让flask实例 注册蓝图 register_blueprint(蓝图) 功能和主程序分离,注册 5. send_file jsonify send_file() # 打开文件并返回,并加入返回头 jsonify # 将字典json后,加入返回头applction/json 6.特殊装饰器: before_request: 请求进入视图函数以前执行 after_request: 响应返回前端以前执行 errorhandler(404): 错误响应 before_first_request: 第一次访问时,请求进入视图函数以前执行 be1 - be2 - af2 - af1 be1 - af2 - af1 7.闪现 flash: flash("内容","标签") get_flashed_messages() get_flashed_messages(category_filter=["标签"])