一篇博客带你入门Flask
一. Python 现阶段三大主流Web框架 Django Tornado Flask 对比
1.Django 主要特点是大而全,集成了很多组件,例如: Models Admin Form 等等, 不管你用得到用不到,反正它全都有,属于全能型框架
2.Tornado 主要特点是原生异步非阻塞,在IO密集型应用和多任务处理上占据绝对性的优势,属于专注型框架
3.Flask 主要特点小而轻,原生组件几乎为0, 三方提供的组件请参考Django 非常全面,属于短小精悍型框架
Django 通常用于大型Web应用由于内置组件足够强大所以使用Django开发可以一气呵成
Tornado 通常用于API后端应用,游戏服务后台,其内部实现的异步非阻塞真是稳得一批
Flask 通常应用于小型应用和快速构建应用,其强大的三方库,足以支撑一个大型的Web应用
Django 优点是大而全,缺点也就暴露出来了,这么多的资源一次性全部加载,肯定会造成一部分的资源浪费
Tornado 优点是异步,缺点是干净,连个Session都不支持
Flask 优点是精悍简单,缺点可能就是你不会!
Flask打印我们万能的HelloWorld
- pip install Flask
Flask中的HttpResponse Render Redirect
HttpResponse
在Flask 中的HttpResponse 在我们看来其实就是直接返回字符串
Redirect
render(render_template)
Flask里面的render对应的是render_template
后面直接跟html文件名,只要改html文件建在同目录下的templates文件夹中,会自动匹配
Flask处理函数返回值的其他类型方法
jsonify
类似与Django里面的JsonResponse,返回json序列化后的数据,在Flask项目中需要对数据进行序列化传输时,用这个比json.dumps要好很多
send_file
返回文件类型的数据(图片、视频等)
注意注意:一定要注意,用jsonify序列化数据时,数据格式必选严格满足json格式,单引号的字符串也不行,它不像json在序列化时会将单引号变成单引号。而它不行!
Flask中的request对象
methods=["POST"] 代表这个url地址对应的视图函数只允许 POST 请求,是个列表也就是意味着可以允许多重请求方式,例如GET之类的
request.method
与Django里面的方法一致,获取本次请求的请求方式
request.form
获取前端用form表单提交过来的数据
- print(request.form) # ImmutableMultiDict([('user', 'Oldboy'), ('pwd', 'DragonFire')])
- # ImmutableMultiDict 它看起来像是的Dict 就用Dict的方法取值试一下吧
- print(request.form["user"]) # Oldboy
- print(request.form.get("pwd")) # DragonFire
- # 看来全部才对了, ImmutableMultiDict 似乎就是个字典,再来玩一玩它
- print(list(request.form.keys())) # ['user', 'pwd'] 看来是又才对了
request.args
获取url中传递过来的所有参数值
然后会在控制台中看到 ImmutableMultiDict([('id', '1'), ('age', '20')]),获取到的数据直接当作字典进行操作即可
request.args 与 request.form 的区别就是:
request.args 是获取url中的参数
request.form 是获取form表单中的参数
request.values
只要是参数,无论是post过来的还是get过来我全部接受
- print(request.values) # CombinedMultiDict([ImmutableMultiDict([('id', ''), ('age', '')]), ImmutableMultiDict([('user', 'Oldboy'), ('pwd', 'DragonFire')])])
- print(request.values.get("id")) #
- print(request.values["user"]) # Oldboy
- # 这回喜欢直接操作字典的小伙伴们有惊喜了! to_dict() 方法可以直接将我们的参数全部转为字典形式
- print(request.values.to_dict()) # {'user': 'Oldboy', 'pwd': 'DragonFire', 'id': '', 'age': ''}
同样获取到的数据直接当成一个大字典进行操作即可
注意啦!注意啦!
- # 注意这里的坑来啦! 坑来啦!
- # 如果url和form中的Key重名的话,form中的同名的key中value会被url中的value覆盖
- # http://127.0.0.1:5000/req?id=1&user=20
- print(request.values.to_dict()) # {'user': 'pwd': 'DragonFire', 'id': ''}
request.headres
用来获取本次请求的请求头
- print(type(request.headers))
- """
- Host: 127.0.0.1:
- User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/ Firefox/60.0
- Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
- Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
- Accept-Encoding: gzip, deflate
- Referer: http://127.0.0.1:5000/home
- Content-Type: application/x-www-form-urlencoded
- Content-Length: 26
- Cookie: csrftoken=vDIozqveCEfArdYXlM6goHVlSQEn7h4bDygNphL2Feas60DiM2di0jlqKfxo7xhA
- Connection: keep-alive
- Upgrade-Insecure-Requests: 1
- Cache-Control: max-age=0
- """
获取请求头
request.data
没有加请求头的数据都可以在这个里面找到,并且是bytes类型
request.files
如果遇到文件上传的话,request.files 里面存的是你上传的文件,但是 Flask 在这个文件的操作中加了一定的封装,让操作变得极为简单
- my_file = request.files["file"]
- my_file.save("test.txt") # 保存文件,里面可以写完整路径+文件名
这样我们就成功的保存了一个名叫 "test.txt" 的文件了,操作还是很简单的
request.获取各种路径
- # 获取当前的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/
request.json
如果在请求中写入了 "application/json" 使用 request.json 则返回json解析数据, 否则返回 None
Flask中的模板语言Jinja2以及render_template的深度用法
Flask对Jinja2稍微做了一点点的加工修饰
针对传入是字典的数据对象操作
- <tr>
- <td>{{ student.name }}</td>
- <td>{{ student["age"] }}</td>
- <td>{{ student.get("gender") }}</td>
- </tr>
针对传入是列表套字典对象的操作
- STUDENT_LIST = [
- {'name': 'Old', 'age': , 'gender': '中'},
- {'name': 'Boy', 'age': , 'gender': '男'},
- {'name': 'EDU', 'age': , 'gender': '女'}
- ]
- <tr>
- <td>{{ foo }}</td>
- <td>{{ foo.name }}</td>
- <td>{{ foo.get("age") }}</td>
- <td>{{ foo["gender"] }}</td>
- </tr>
针对传入的是{1:{}}这种大字典类型
- STUDENT_DICT = {
- : {'name': 'Old', 'age': , 'gender': '中'},
- : {'name': 'Boy', 'age': , 'gender': '男'},
- : {'name': 'EDU', 'age': , 'gender': '女'},
- }
- <tr>
- <td>{{ foo }}</td>
- <td>{{ student.get(foo).name }}</td>
- <td>{{ student[foo].get("age") }}</td>
- <td>{{ student[foo]["gender"] }}</td>
- </tr>
后端传入多个数据类型,采用赋值语句传值方式,一个一个传!
- @app.route("/allstudent")
- def all_student():
- return render_template("all_student.html", student=STUDENT ,
- student_list = STUDENT_LIST,
- student_dict= STUDENT_DICT)
Jinja2 的高阶用法
safe(前端入手)
将你写的html代码直接渲染不转译
Markup(后端入手)
- from flask import Flask
- from flask import render_template
- from flask import Markup # 导入 flask 中的 Markup 模块
- app = Flask(__name__)
- @app.route("/")
- def index():
- tag = "<input type='text' name='user' value='DragonFire'>"
- markup_tag = Markup(tag) # Markup帮助咱们在HTML的标签上做了一层封装,让Jinja2模板语言知道这是一个安全的HTML标签
- print(markup_tag,
- type(markup_tag)) # <input type='text' name='user' value='DragonFire'> <class 'markupsafe.Markup'>
- return render_template("index.html", tag=markup_tag)
- app.run("0.0.0.0", , debug=True)
类似于Django里面的mark_safe()
模板中执行函数
先在后端中定义函数,类似于Django中的sample_tag/inclusion_tag等
- from flask import Flask
- from flask import render_template
- from flask import Markup # 导入 flask 中的 Markup 模块
- app = Flask(__name__)
- #定义一个函数,把它传递给前端
- def a_b_sum(a,b):
- return a+b
- @app.route("/")
- def index():
- return render_template("index.html", tag=a_b_sum)
- app.run("0.0.0.0", , debug=True)
通过tag参数将我们写的函数传递到前端页面
前端代码
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- {{ tag }}
- <br>
- {{ tag(,) }}
- </body>
- </html>
看到结果就是,函数加()执行得到结果
还可以定义全局函数template_global(),无需后端传递给前端,Jinja2直接就可以执行的函数
对于这种处理函数,还可以有一种偏函数template_filter()的应用,管道符前面的值作为函数的第一个参数传入函数中
- from flask import Flask
- from flask import render_template
- from flask import Markup # 导入 flask 中的 Markup 模块
- app = Flask(__name__)
- @app.template_global() # 定义全局模板函数
- def a_b_sum(a, b):
- return a + b
- @app.template_filter() # 定义全局模板函数
- def a_b_c_sum(a, b, c):
- return a + b + c
- @app.route("/")
- def index():
- return render_template("index.html", tag="")
- app.run("0.0.0.0", , debug=True)
前端代码
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- {{ a_b_sum(,) }}
- <br>
- {{ | a_b_c_sum(,) }}
- </body>
- </html>
管道符前面也可以是一个函数,会将函数的返回值作为后面函数的第一个参数
Jinja2模板复用 block
跟Django里面的block模板语言一模一样,还有模板继承语言extends,模板应用语言include。跟Django里面的是一模一样的用法,这里不做赘述
Jinja2模板语言中的宏定义
简单的说就是在前端页面中直接定义函数,并直接在前端调用执行定义的函数
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <h1>Welcome OldboyEDU</h1>
- {% 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>
宏定义一般情况下很少应用到,但是要知道有这么个概念,起码能吹个牛逼见识广博!
Flask实战
需求:
1. 用户名: oldboy 密码: oldboy123
2. 用户登录成功之后跳转到列表页面
3. 失败有消息提示,重新登录
4.点击学生名称之后,可以看到学生的详细信息
- from flask import Flask
- from flask import request
- from flask import render_template
- from flask import redirect
- USER = {'username': 'oldboy', 'password': "oldboy123"}
- STUDENT_DICT = {
- : {'name': 'Old', 'age': , 'gender': '中'},
- : {'name': 'Boy', 'age': , 'gender': '男'},
- : {'name': 'EDU', 'age': , 'gender': '女'},
- }
- app = Flask(__name__)
- @app.route("/login", methods=["GET", "POST"])
- def login():
- if request.method == "POST":
- if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]:
- return redirect("/student_list")
- return render_template("login.html", msg="用户名密码错误")
- return render_template("login.html", msg=None) # 如果前端Jinja2模板中使用了msg,这里就算是传递None也要出现msg
- @app.route("/student_list")
- def student():
- return render_template("student_list.html", student=STUDENT_DICT)
- @app.route("/info")
- def student_info():
- stu_id = int(request.args["id"])
- stu_info = STUDENT_DICT[stu_id]
- return render_template("student.html", student=stu_info, stu_id=stu_id)
- app.run("0.0.0.0", , debug=True)
- 相信写的代码才是最好的
后端
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Welcome to Old Boy EDU</title>
- </head>
- <body>
- <form method="post">
- 用户名:<input type="text" name="username">
- 密码:<input type="text" name="password">
- <input type="submit" value="登录">
- {{ msg }}
- </form>
- </body>
- </html>
- 登录页面前端代码
login.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Old Boy EDU</title>
- </head>
- <body>
- Welcome to Old Boy EDU
- <table border="2xp">
- <thead>
- <tr>
- <td>id</td>
- <td>name</td>
- <td>option</td>
- </tr>
- </thead>
- <tbody>
- {% for foo in student %}
- <tr>
- <td>{{ foo }}</td>
- <td>{{ student[foo].name }}</td>
- <td><a href="/info?id={{ foo }}">详细</a></td>
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </body>
- </html>
- 一点儿也不难
student_list.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Old Boy EDU</title>
- </head>
- <body>
- Welcome to Old Boy EDU
- <table border="1px">
- <thead>
- <tr>
- <td>id</td>
- <td>name</td>
- <td>age</td>
- <td>gender</td>
- </tr>
- </thead>
- <tbody>
- <tr>
- <td>{{ stu_id }}</td>
- <td>{{ student.name }}</td>
- <td>{{ student["age"] }}</td>
- <td>{{ student.get("gender") }}</td>
- </tr>
- </tbody>
- </table>
- <div><a href="/student_list">返回</a></div>
- </body>
- </html>
- 写不出来说明你没动脑子
student.html
Flask中的内置Session
Flask中的Session非常的奇怪,他会将你的SessionID存放在客户端的Cookie中,使用起来也非常的奇怪
1. Flask 中 session 是需要 secret_key 的(前提条件必须满足!)
- from flask import session
- app = Flask(__name__)
- app.secret_key = "session_key"
secret_key 实际上是用来加密字符串的,如果在实例化的app中没有 secret_key 那么开启session一定会抛异常的
2. session 要这样用
- @app.route("/login", methods=["GET", "POST"])
- def login():
- if request.method == "POST":
- if request.form["username"] == USER["username"] and request.form["password"] == USER["password"]:
- session["user"] = USER["username"]
- return redirect("/student_list")
- return render_template("login.html", msg="用户名密码错误")
- return render_template("login.html", msg=None) # 如果前端Jinja2模板中使用了msg,这里就算是传递None也要出现msg,防止报错!
session["user"] = USER["username"] 这样用就代表这个请求带上来的session中保存了一个user=name,后续就可以直接在session.get("user")中拿到设置的值
3. 怎么用 session 进行验证呢?
- @app.route("/student_list")
- def student():
- if session.get("user"):
- return render_template("student_list.html", student=STUDENT_DICT)
- return redirect("/login")
Flask中的路由系统
Flask中的路由系统其实我们并不陌生了,从一开始到现在都一直在应用
@app.route("/",methods=["GET","POST"])
1. @app.route() 装饰器中的参数
methods : 当前 url 地址,允许访问的请求方式(当前装饰的视图函数支持的请求方式)
- @app.route("/info", methods=["GET", "POST"])
- def student_info():
- stu_id = int(request.args["id"])
- return f"Hello Old boy {stu_id}" # Python3.6的新特性 f"{变量名}"
endpoint : 反向url地址,默认为视图函数名 (url_for)
- from flask import url_for
- @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 Old boy {stu_id}" # Python3.6的新特性 f"{变量名}"
对比Django里面的url反向解析,这里相当于路由解析url
defaults : 视图函数的参数默认值{"nid":1}
- from flask import url_for
- @app.route("/info", methods=["GET", "POST"], endpoint="r_info", defaults={"nid": })
- def student_info(nid):
- print(url_for("r_info")) # /info
- # stu_id = int(request.args["id"])
- print(nid) #
- return f"Hello Old boy {nid}" # Python3.6的新特性 f"{变量名}"
不常用
strict_slashes : url地址结尾符"/"的控制 False : 无论结尾 "/" 是否存在均可以访问 , True : 结尾必须不能是 "/",这一点不像Django会帮我们自动补全/
- # 访问地址 : /info
- @app.route("/info", strict_slashes=True)
- def student_info():
- return "Hello Old boy info"
- # 访问地址 : /infos or /infos/
- @app.route("/infos", strict_slashes=False)
- def student_infos():
- return "Hello Old boy infos"
redirect_to : url地址重定向
需要注意的是这里的重定向并不是我们之前接触到那种先访问出一个页面,然后再跳转,而是直接在后端内部直接给你做重定向,可以称为内重定向。举个例子,相当于我有一个网站已经投入使用很久了,用户都将网站的地址收藏了,这个时候我需要扩展网站功能和修改部分功能,这些新功能对应的地址用户有又不知道,这个时候就可以在后端直接用上内重定向的方式,让用户访问的url在我们的服务器内部直接给他重定向到我们新的url地址中
- # 访问地址 : /info 浏览器跳转至 /infos
- @app.route("/info", strict_slashes=True, redirect_to="/infos")
- def student_info():
- return "Hello Old boy info"
- @app.route("/infos", strict_slashes=False)
- def student_infos():
- return "Hello Old boy infos"
subdomain : 子域名前缀 subdomian="DragonFire" 这样写可以得到 DragonFire.oldboyedu.com 前提是app.config["SERVER_NAME"] = "oldboyedu.com"
- app.config["SERVER_NAME"] = "oldboy.com"
- @app.route("/info",subdomain="DragonFire")
- def student_info():
- return "Hello Old boy info"
- # 访问地址为: DragonFire.oldboy.com/info
对于初始化配置,我们需要知道的几种不同的配置方式:
app.config.from_object("setting.FlaskSetting")
app.DEBUG = True 开启Debug模式,该完代码不用手动重启
app.SECRET_KEY = "xxxxx" 开启session必备参数
app.config['DEBUG']=True
app.run(debug=True)
2.动态参数路由:
- from flask import url_for
- # 访问地址 : http://127.0.0.1:5000/info/1
- @app.route("/info/<int:nid>", methods=["GET", "POST"], endpoint="r_info")
- def student_info(nid):
- print(url_for("r_info",nid=)) # /info/
- return f"Hello Old boy {nid}" # Python3.6的新特性 f"{变量名}"
<int:nid> 就是在url后定义一个参数接收,并且要是int类型,也可不加限制
但是这种动态参数路由,在url_for的时候,一定要将动态参数名+参数值添加进去,否则会抛出参数错误的异常
Flask实例化参数及配置
- from flask import Flask
- app = Flask(__name__) # type:Flask
- app.config["DEBUG"] = True
这句 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': , # 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 会拒绝内容长度大于此值的请求进入,并返回一个 状态码
- 'SEND_FILE_MAX_AGE_DEFAULT': , # 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- 来编码它然后才进行传输。
- 'JSON_SORT_KEYS': True,
- #默认情况下 Flask 按照 JSON 对象的键的顺序来序来序列化它。
- # 这样做是为了确保键的顺序不会受到字典的哈希种子的影响,从而返回的值每次都是一致的,不会造成无用的额外 HTTP 缓存。
- # 你可以通过修改这个配置的值来覆盖默认的操作。但这是不被推荐的做法因为这个默认的行为可能会给你在性能的代价上带来改善。
- 'JSONIFY_PRETTYPRINT_REGULAR': True,
- 'JSONIFY_MIMETYPE': 'application/json',
- 'TEMPLATES_AUTO_RELOAD': None,
- }
配置参数大全
修改配置的方式大约是两种
1.直接对app.config进行修改
- app.config["DEBUG"] = True
2.使用类的方式导入
首先要有一个settings.py的文件
- class FlaskSetting:
- DEBUG = True
- SECRET_KEY = "DragonFire"
然后我们在Flask的启动文件中就可以这么写
- from flask import Flask
- app = Flask(__name__) # type:Flask
- app.config.from_object("settings.FlaskSetting")
它会自动对字符串路径进行处理并导入,相当于importlib
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: 则无法通过当前的路由
- 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 目录
这三个参数在后面的Flask蓝图会起到很大的作用
Flask中的蓝图(Blueprint)
Flask的蓝图,你可以看成是一个个小的组件,分别能够实现部分功能,在我的主运行文件中只需要将这些蓝图全部注册进来,就可以将这些分散的功能组合成一个整体,这非常符合实际开发需求,十个人可以同时开发不同的功能,最后直接统一注册整合即可拼成“真正的伟大蓝图”
1.初识Flask蓝图(blueprint)
注册蓝图的时候,可以给某个蓝图再添加一个url前缀
Flask中的before_request,after_request
我们现在有一个 Flask 程序其中有3个路由和视图函数,如下:
- from flask import Flask
- app = Flask(__name__) # type:Flask
- @app.route("/login")
- def login():
- return "Login"
- @app.route("/index")
- def index():
- return "Index"
- @app.route("/home")
- def home():
- return "Login"
- app.run("0.0.0.0", )
- 简单的小程序
小程序
如果登陆了,就可以访问 index 和 home 页面,如果没登录就跳转到 login 登录
要怎么解决呢, session 对, 用 session 除了 Login 函数之外的所有函数里面全校验 session 是否登录了
太麻烦了,现在咱们只有3个函数,如果成百上千个怎么整啊
装饰器,对没错,装饰器是一个很好的方案,但是啊,我现在还是成败上千个函数,我要在每一个函数定义的时候加上@装饰器,还是很麻烦
那么就引出了我们要学习的第一个知识点:
1.@app.before_request 在请求(request)之前做出响应
- from flask import Flask
- from flask import request
- from flask import redirect
- from flask import session
- app = Flask(__name__) # type:Flask
- app.secret_key = "DragonFire"
- @app.before_request
- def is_login():
- if request.path == "/login":
- return None
- 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 "Login"
- app.run("0.0.0.0", )
解决所有问题
@app.before_request 也是一个装饰器,他所装饰的函数,都会在请求进入视图函数之前执行
request.path 是来读取当前的url地址如果是 /login 就允许直接通过 return None 你可以理解成通过放行
校验session中是否有user 如果没有的话,证明没有登录,所以毫不留情的 redirect("/login") 跳转登录页面
还有一个要提的 @app.before_first_request 它与 @app.before_request 极为相似或者说是一模一样,只不过它只会被执行一次
看到这里,学过Django的小伙伴们应该有一种似曾相似的感觉,就是这个方法特别像Django里面的中间件process_request方法~~~
2. @app.after_request 在响应(response)之前做出响应
- @app.after_request
- def foot_log(environ):
- if request.path != "/login":
- print("有客人访问了",request.path)
- return environ
这个则类似于Django里面的process_response方法
3.@app.errorhandler(状态码)自动捕获状态码做出相应操作
函数接收的args参数就是原始的报错信息
404 Not Found: The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
总结
如果我们在Flask中定义了还几个before_request和after_request装饰函数,如果在经历第一个before_request函数后就被拦截下来,那么如果是Django的中间件则会直接找到同一位置上的process_response去执行返回,而Flask中则是要走所有的after_request方法,无论你是在哪个before_request方法上被拦截的
一篇博客带你入门Flask的更多相关文章
- 一篇博客带你轻松应对java面试中的多线程与高并发
1. Java线程的创建方式 (1)继承thread类 thread类本质是实现了runnable接口的一个实例,代表线程的一个实例.启动线程的方式start方法.start是一个本地方法,执行后,执 ...
- 一篇博客带你轻松应对Springboot面试
1. SpringBoot简介 SpringBoot是简化Spring应用开发的一个框架.他整合了Spring的技术栈,提供各种标准化的默认配置.使得我们可以快速开发Spring项目,免掉xml配置的 ...
- 通通的最后一篇博客(附自制html5平面射击小游戏一枚)
这是我最后一篇博客了,由于本人的人生规划吧,以后应该也写不出什么好的技术文章了,到现在在博客园写了2年, 今天一看,我也有了120个粉丝,好几万的浏览量,感谢大家的支持啊~~ 半年没有写博客了,由于半 ...
- 第一篇博客 ---- 分享关于Maven使用的一些技巧
Maven环境搭建 在官网上下载maven安装包,地址:http://maven.apache.org/download.cgi . 解压文件到电脑坐在盘符目录,如E:\apache-maven-3. ...
- 用flask开发个人博客(4)—— flask中4种全局变量
https://blog.csdn.net/hyman_c/article/details/53512109 一 current_app current_app代表当前的flask程序实例,使用时需 ...
- 小白两篇博客熟练操作MySQL 之 第二篇
小白两篇博客熟练操作MySQL 之 第二篇 一. 视图 视图是一个虚拟表,其本质是根据SQL语句获取动态的数据集,并为其命名,用户使用时只需使用名称即可获取结果集, 并可以将其当做表来使用. s ...
- [书籍]值得纪念的第100篇博客,推荐一些看过的UI书籍
1. 前言 来到博客园11年,这两年闲下来了才有时间写写博客,不知不觉终于写到第100篇博客了.回顾过去发表的博客,居然大部分都与UI相关.明明我本来从事的是Oracle的相关开发,明明我当初的目标是 ...
- Hexo结合Stun静态博客搭建从入门到入土
摘要 安装npm,安装hexo相关依赖,安装主题stun 修改hexo配置,修改stun配置,部署到github,gitee实现静态访问 给博客加上全局搜索,访问量统计 hexo博客编写模板 tips ...
- 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 百篇博客分析OpenHarmony源码 | v53.02
百篇博客系列篇.本篇为: v53.xx 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应 ...
随机推荐
- Spring拓展接口之BeanFactoryPostProcessor,占位符与敏感信息解密原理
前言 开心一刻 一只被二哈带偏了的柴犬,我只想弄死隔壁的二哈 what:是什么 BeanFactoryPostProcessor接口很简单,只包含一个方法 /** * 通过BeanFactoryPos ...
- ubuntu开发项目不能执行热更新
当项目开发到一定成熟度,项目基本上比较大(vue,angular,react,java,php等),在Ubuntu系统环境下,我们写了代码,但是不能想Windows一样执行热更新,这是因为Ubuntu ...
- 第53章 结束会话端点(End Session Endpoint) - Identity Server 4 中文文档(v1.0.0)
结束会话端点可用于触发单点注销(请参阅规范). 要使用结束会话端点,客户端应用程序会将用户的浏览器重定向到结束会话URL.用户在会话期间通过浏览器登录的所有应用程序都可以参与注销. 注意 终端会话端点 ...
- C# 设置Excel条件格式(二)
上一篇文章中介绍了关于设置Excel条件格式,包括基于单元格值.自定义公式等应用条件格式.应用数据条条件类型格式.删除条件格式等内容.在本篇文章中将继续介绍C# 设置条件格式的方法. 要点概述: 1. ...
- Java消息中间件----ActiveMQ入门①
一 首先到ActiveMQ下载安装包 Active官网地址http://activemq.apache.org/activemq-5150-release.html 如图所示,有两个下载的链接,我们下 ...
- Eclipse Ctrl+Space 无法工作的问题
Window->preference->Keys 然后找到content Assist,然后重新设置为自己想要的Short cut 就好了
- 此博客停更,转至lustforlife.cn
新博客地址:lustforlife.cn
- git 常用命令,上传,下载,更新线上代码
git 常用命令以及推荐git新建上传个人博客 $ git clone //本地如果无远程代码,先做这步,不然就忽略 $ git status //查看本地自己修改了多少文件 $ git add . ...
- 上海启动5G试用!104页PPT,为你深度解析5G终端的创新和机遇
文章发布于公号[数智物语] (ID:decision_engine),关注公号不错过每一篇干货. 来源:国泰君安证券 作者:分析师王聪.张阳.陈飞达 导读:2019年是5G元年,各大品牌将陆续推出5G ...
- 自定义一个全屏的AlertDialog。
........... final MyDialog dialog = new MyDialog(this); LayoutInflater inflater = getLayoutInflater( ...