Flask 轻便的web框架-1

内容简述

1.Flask与django对比

  • 框架对比

    Django Flask
    Admin -Model 原生无
    Model 原生无
    Form表单 原生无
    Session 有--->特殊
    第三方组件特别多
  • Flask:宗旨:以简单为基准 开发一切从简 能省则省

2.Django与Flask的优势劣势对比:

  • django:

    • 优势:组件全,功能全,教科书
    • 劣势:占用资源,创建复杂度较高
  • Flask:

    • 优势:轻量级,速度快
    • 劣势:先天不足,第三方组件稳定性较差

3.入门Flask

  • pip3 install Flask 不要使用工具中的插件创建Flask项目
  • 三行代码启动Flask项目

  • 附属模块:

    • jinjia2 :Jinja2是Python一个被广泛应用的模版引擎,他的设计思想来源于Django的模板引擎。
    • MarkupSafe 用于render底层,防XSS攻击
    • werkzeug ------->uwsgi一个网关接口,是PythonWSGI规范的实用函数库。使用广泛,基于BSD协议
    • BSD:"伯克利软件发行版",一整套软件发行版的统称

4.一个简单Flask:

from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
	return "Hello world!"
if __name__ == '__main__':
    app.run()
  • route:一个装饰器,用于为给定的URL规则注册视图函数。

5.web框架的Response三剑客:

  • HTTPResponse
  • redirect
  • render

Content-Type:text/html 为text文本类型,要用html渲染

  • render_template
  • send_file
  • jsonify
  • render_template()
from flask import Flask, render_template, redirect, send_file, jsonify
app = Flask(__name__)


@app.route("/")
def home():
    return "Hello World I am Flask"

@app.route("/index")
def index():
    return render_template("index.html")

@app.route("/login")
def login():
    return redirect("/index")

@app.route("/get_file")
def get_file():
    return send_file("app01.py")

@app.route("/get_json")
def get_json():
    #alt + enter
    return jsonify("hello json")#返回标准Json格式字符串


app.run()
  • 母版配置
    • 项目下新建templates,点击鼠标右键,Mark Directory as--->Template Folder

6.send_file()

  • 返回是一个instance类型

  • 会自动识别文件类型,Content-type中添加文件类型,Content-type:文件类型

  • 保留当前文件格式

  • 示例:

    from flask import Flask,send_file
    
    app = Flask(__name__)
    
    @app.route("/")
    def TestDemo():
        return send_file("demo3.py")#返回文件内容,字符串
    @app.route("/get_file")
    def get_file():
        return send_file("文咏珊.jpg")#send_file会自动是被文件类型,Content-type中添加文件类型
    @app.route("/get_music")
    def get_music():
        return send_file("音乐.mp3")#send_file会自动是被文件类型,Content-type中添加文件类型
    @app.route("/get_video")
    def get_video():
        return send_file("电影.mp4")#send_file会自动是被文件类型,Content-type中添加文件类型
    if __name__ == '__main__':
        app.run()
    
  • 浏览器特性 可识别Content-type 自动渲染

  • 不可识别的Content-type 会自动下载

- content_type:image/jpeg  返回类型为一张图片
- content_type:audio/mpeg:返回类型为一张图片
- content_type :video.mp4:返回类型为一个电影
- application/x-msdownload:返回一个可下载类型
- Content-Type: application/json  返回一个Json

7.jsonify() str

  • 返回标准格式的json字符串 先序列化json的字典,Content-type中加入Application/json
  • flask 1.1.1版本中可以直接返回字典格式无序jsonify

from flask import Flask,send_file,jsonify

app = Flask(__name__)
@app.route("/get_json")
def get_json():
    dic = {"k1":"v1"}
    return jsonify(dic)#return dic 是一样的


if __name__ == '__main__':
    app.run()
  • 文件特性:

    • 凡是二进制文件的开头,都设置文件类型
  • 浏览器特性:

    • 可根据文件开头描述文件类型。识别的Content-type会自动渲染
    • 当不可识别Content-type 会自动下载

FLASK 1.1.1之后的版本可以直接返回字典等数据类型,flask会自动帮你json序列化

8.flask中的request

  • request.method 获取请求方式

  • request.form 获取FormData中的数据,也就是form标签

    from flask import Flask,request,render_template,Markup
    
    # request:请求上下文管理,机制的实现
    
    app = Flask(__name__)
    
    @app.route("/login",methods=["GET","POST"])
    def login():
        # 如果是get请求  返回登录页面
        if request.method == "GET":
            return render_template("login.html")
    
        #如果是post请求,获取用户名密码  校验
        else:#405   表示请求方式不被允许
            # 表示直接可将ImmutableMultiDict对象转换成字典
            print(request.form.to_dict())  # 这里form指的是浏览器提交的Form表单数据(FormData)
            print("request.form------>", request.form)#   ImmutableMultiDict([('username', 'xjk'), ('password', '123')])
            print(request.form["username"])#法1:获取用户名
            print(request.form.get("username"))#法2:获取用户名
    
            if request.form.get("username") == "ywb":
                return "Login ok!"
        return "Login 失败"
    if __name__ == '__main__':
        app.run()
    
  • request.args 获取URL中的数据 to_dict()

    #http://127.0.0.1:5000/get_json?id=1
    
    def get_json():
        print(request.args.to_dict())#{'id': '1'}
        dic = {"k1":"v1"}
        return dic
    
  • request.values 获取url和FormData中的数据(to_dict() url会覆盖FormData)

  • request.json 请求中Content-Type : application/json 请求体中的数据,被序列化到request.json中,以字典形式存放

  • request.data 请求中符合Content-Type类型,但不包含Form或FormData 保留请求体中的原始数据 是一个b""

  • request.files 获取Form中的文件

  • request.path 请求路径,路由地址

  • request.url 访问请求的完整路径包括url参数

  • request.host 主机位

  • request.cookies 字典获取浏览器请求时带上cookies

9.文件上传

  • 注意前端form表单加 enctype="multipart/form-data"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post" enctype="multipart/form-data">
    <input type="file" name="my_file">
    <button type="submit">提交</button>
</form>

</body>
</html>

from flask import Flask, request, render_template
import os
app = Flask(__name__)


@app.route("/upload",methods=["GET","POST"])
def upload():
    #判断请求是方式
    if request.method == "GET":
        return render_template("upload.html")
    if request.method == "POST":
        my_file = request.files.get("my_file")
        print(my_file,type(my_file))#<FileStorage: '文咏珊.jpg' ('image/jpeg')> <class 'werkzeug.datastructures.FileStorage'>
        """
        stream=None,
        filename=None,
        name=None,
        content_type=None,
        content_length=None,
        headers=None,
        """
        print("stream-->",my_file.stream)#<tempfile.SpooledTemporaryFile object at 0x00000192D5D04BA8>
        print("name-->",my_file.name)#my_file
        print("content_type-->",my_file.content_type)#image/jpeg
        print("headers-->",my_file.headers)#Content-Disposition: form-data; name="my_file"; filename="文咏珊.jpg"


        filename = my_file.filename  #获取原始文件名
        file_path = os.path.join("avatar",filename)
        my_file.save(file_path)#将文件内容存入指定路径下
        return "上传完毕"
    return "上传失败"

if __name__ == '__main__':
    app.run(host="127.0.0.1",port="5000",debug=True)#debug可以在此设置,如果给定,启用或禁用调试模式。
    
    或者:
    	app.debug = True
        app.config["DEBUG"] = True
        3选1均可

10jinja2

  • Flask的模版语言
    • {{ }} 引用或执行
    • {%%} 逻辑引用

10.1函数在模版中应用

  • 返回数值相加之和
@app.template_global()
def add_num(a,b):
    return a+b
    
    
模版应用:<p>{{ add_num(50,60) }}</p>
  • 返回html标签
from markupsafe import Markup
@app.template_global()
def my_input(na,ty):
    s = f"<input type='{ty}' value='{na}'>"
    return Markup(s)
模版应用:{{ my_input("上传","submit") }}
  • 直接在模版书写----->宏指令
<div>密码:
    {% macro my_input(na,ty) %}
    <input type="{{ ty }}" name="{{ na }}">
    {% endmacro %}

    {{ my_input("pwd","password") }}
</div>

  • 在模板中如何添加数据
obj.get('name')
obj["name"]

{%for skey,svalue in obj.items()%}
{%endfor%}

{%for skey in obj%}
{%endfor%}

  • 示例:
<body>
    {% for i in t %}
        <div>{{ i }}</div>
    {% endfor %}
    <div>I am a index</div>
</body>


@app.route("/index")
def index():
    rest = [1, 2, 3, 4, 5]
    return render_template('index.html',t=rest)

12.flask中的session

  • 基于请求上下文管理机制
#系统定义了全局变量
session = LocalProxy(partial(_lookup_req_object, "session"))
  • 做一个flask的登录
    • 导入模块:from flask import session
    • 设置密钥:app.secret_key = "密钥内容"
    • 登录成功设置session
from flask import Flask, render_template, Markup, request, session, redirect
app = Flask(__name__)
app.debug = True
app.secret_key = "!@#$%^(*&^%$#@#$%&*(^$WQ*(^EWET*^EWEU"


@app.route("/login",methods=["GET","POST"])
def login():
    if request.method == "POST":
        print(request.form)#ImmutableMultiDict([('username', 'admin'), ('password', '123')])
        user = request.form.get("username","")
        pwd = request.form.get("password","")
        

        if user == "admin" and pwd == "123":
            session["user"] = user#登录成功,给session设置值
            return "登录成功"
    #交由客户端保管机制
    print(session.get("user"))
    return render_template("login.html")

if __name__ == '__main__':
    app.run()

13values的坑(慎用)

#my_login.html
<form action="?id=101&user=20" method="post">
    账号:<input type="text" name="user">
    密码:<input type="password" name="pwd">
    <input type="submit" value="提交">
</form>

#函数
@app.route("/mlogin",methods=["GET","POST"])
def my_login():
    if request.method == "GET":
        return render_template("my_login.html")
    if request.method == "POST":
        print(request.values)
        print(request.values.to_dict())
        return "来了老弟"
    
#CombinedMultiDict([ImmutableMultiDict([('id', '101'), ('user', '20')]), ImmutableMultiDict([('user', 'wxx'), ('pwd', '123')])])
#{'user': '20', 'pwd': '123', 'id': '101'}   

  • 当url和form中的Key重名的话,form中的同名的key中value会被url中的value覆盖

14.给多个函数加同一个装饰器

  • 法1:

    import functools
    在装饰器inner里加入@functools.wraps(func)
    functools.wraps(func)相当于保留元信息
    如果不加,会报错:
    AssertionError: View function mapping is overwriting an existing endpoint function: inner
    
    不加效果等同于inner = inner(detail())
    如果加了装饰器,效果等同于inner.__name__ = func.__name__ 其函数名字得以保留
    
  • 示例:

    def wrapper(func):
        @functools.wraps(func)
        def inner(*args,**kwargs):
    
            session_key = session.get("user")
            if session_key:
                ret = func(*args,**kwargs)
                return ret
            else:
                return redirect('/login')
        return inner
    
原文地址:https://www.cnblogs.com/xujunkai/p/12348920.html