最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

天天最资讯丨Flask

来源:博客园


(资料图片仅供参考)

Flask

1.Flask和pythonweb框架介绍

django:大而全 内置的app多 第三方的app也多    flask:小而精 没有过多的内置组件 只完成web框架最基本的功能 需要借助于第三方 完成更丰富的功能web.py:是一个小巧灵活的pethon框架 它简单而且功能强大     异步web框架:fastapi:python的异步web框架 详细参考:https://fastapi.tiangolo.com/zh/    sanic:python的异步web框架 供支持异步高并发请求的web服务tornado:异步框架 用的比较少

1.1同步框架和异步框架的区别

django是同步框架还是异步框架 django3.x以后支持异步同步框架:一个线程只能处理一个请求异步框架:一个线程可以处理多个请求"""异步框架可以很显著的提高并发量"""

1.2 flask介绍

flask是一个基于python开发并且依赖jinjia2模板和werkzeug WSGI服务的一个微型框架jinjia2模板语法:和django的dtl 非常像    werkzeug WSGI 符合wsgi协议的web服务 django使用的是wsgiref

1.2.1wsgiref写web

from wsgiref.simple_server import make_server#mya 就等同于djangodef mya(environ, start_response):    #把environ包装成了request    print(environ)    start_response("200 OK", [("Content-Type", "text/html")])    if environ.get("PATH_INFO") == "/index":        with open("index.html","rb") as f:            data=f.read()    elif environ.get("PATH_INFO") == "/login":        with open("login.html", "rb") as f:            data = f.read()    else:        data=b"

Hello, web!

" return [data] # 做成了responseif __name__ == "__main__": myserver = make_server("", 8008, mya) print("监听8010") myserver.serve_forever() #使用werkzeug写webfrom werkzeug.wrappers import Request, Response@Request.applicationdef hello(request): return Response("Hello World!")if __name__ == "__main__": from werkzeug.serving import run_simple run_simple("localhost", 4000, hello)

2.flask快速使用

#安装:pip install flask#安装依赖:MsrkupSafe、werkzeug、jinjia2、flask

代码:

from flask import Flaskapp = Flask(__name__)#注册路由:@app.route("/index")def index():    return "hello 李李"@app.route("/")def home():    return "李李 home"if __name__ == "__main__":    app.run()

3.登录、显示用户信息小案例

3.1 login.html

        Title

用户名:

密码:

{{error}}

3.2 home.html

        Title

用户列表

{% for k,v in user_dict.items() %} {% endfor %}
{{k}} {{v.name}} {{v["name"]}} {{v.get("name")}} 查看详细

3.3detail.html

        Title

名字是:{{user.name}}

年龄是:{{user["age"]}}

性别是:{{user.get("gender")}}

{{user.text}}

3.4 py文件

from flask import Flask, request, render_template, redirect, session,jsonifyapp = Flask(__name__)# 要使用session,必须设置秘钥,秘钥是配置信息app.secret_key = "asdfasdfa33aef3aefads"USERS = {    1:{"name":"张三","age":18,"gender":"男","text":"道路千万条"},    2:{"name":"李四","age":28,"gender":"男","text":"安全第一条"},    3:{"name":"王五","age":18,"gender":"女","text":"行车不规范"},}# 1 创建templates文件夹,写login.html@app.route("/login", methods=["GET", "POST"])def index():    # 没有request对象,使用全局的request    # get请求,返回模板    if request.method == "GET":        return render_template("login.html")  # 新手四件套之一:返回模板    else:        # post请求,校验数据        # 取出前端传入的用户名密码,校验        username = request.form.get("username")  # 等同于django的的request.POST        password = request.form.get("password")        if username == "lqz" and password == "123":            # 登录成功,保存登录状态 重定向到跟路径   新手四件套之一:重定向            # 保存到session中,session是全局的            session["name"] = username            return redirect("/")        else:            return render_template("login.html", error="用户名或密码错误")  # 注意跟django的render区分,要模板渲染的数据,直接key=value传即可@app.route("/")def home():    # 校验,登录成功,才能过来,不登录,重定向到登录页面    if session.get("name"):  # 有值说明登录了,没有值说明没有登录        return render_template("home.html",user_dict=USERS)    else:        return redirect("/login")@app.route("/detail/")def detail(pk):    if session.get("name"):  # 有值说明登录了,没有值说明没有登录        user_detail = USERS.get(pk)        return render_template("detail.html", user=user_detail)    else:        return redirect("/login")@app.route("/test")def test():    return jsonify([{"name":"lqz","age":19}])if __name__ == "__main__":    app.run()"""# 学到的    1 注册路由  app.route(路径,methods=[请求方式get,post])    2 新手四件套:        -render_template   渲染模板 跟django有区别        -redirect  重定向        -return 字符串 返回字符串        -jsonify 返回json格式            3 请求的request对象,是全局的,直接导入使用即可,在不同视图函数中不会混乱        request.method  请求方式        request.form   post请求的body体的内容转成了字典            4 session 全局的,直接导入使用即可,一定要指定秘钥app.secret_key = "asdfasdfa33aef3aefads"        放值:session["name"]="lqz"        取值:session.get("name")            5 模板的渲染        -兼容django的dtl        -更强大,可以加括号,字典可以.get  .values()   .items()        -{% for %}        6 转换器@app.route("/detail/")"""

配置文件方式

# django 在settings配置# flask也有配置问题 但是他的方式有多种:设置的方式一:测试用app.debug = True   #调试模式 提示信息更详细 修改代码不需要重启 自动重启app.secret_key = "fglqagvuivefew35few" #密钥 只能放debug和secret_key设置方式二:直接使用app.config设置app.config["DEBUG"]=Trueapp.config["SECRET_KEY"]="hgejch"print(app.config)设置方式三:使用py文件(不常用)app.config.from_pyfile("settings.py")print(app.config)设置方式四:常用的 使用类的方式app.config.from_object("settings.DevelopmentConfig")app.config.from_object("settings.ProductionConfig")print("app.config")其他:通过环境变量设置app.config.from_envvar("环境变量名称")json:app.config.from_json("json文件名称")JSON文件名称 必须是json格式 因为内部汇之星json.loads字典格式:配置中心app.config.from_mapping({"DEBUG":True})# 内置的配置字段 其他可以写自己的 比如redis的链接地址 mysql的链接地址DEBUG    SECRET_KEY    SESSION_COOKIE_NAME    PERMANENT_SESSION_LIFETIME

5.路由系统

5.1路由本质

dango中配置路由 在urls中 写path 写在列表中flask是基于装饰器的 大部分都用装饰器来做 少量可以抽取到一个urls.py#路由的装饰器源码分析    @app.route("/login")    def index():        pass    #本质是 --- index =app.route("/login")(index)# app.route("/login")的执行结果 decorator 函数rule 是路径    其他参数都给了options    #然后执行decorator(index)#f是index    endpoint = options.pop("endpoint", None) # 目前没有endpoint,是None    # 核心,本质--》self就是实例化得到的app对象,flask对象    # app对象中有个方法add_url_rule,这是在添加路由    # 不使用装饰器,自己注册路由    self.add_url_rule(rule, endpoint, f, **options)    return f            def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:def decorator(f: T_route) -> T_route:    endpoint = options.pop("endpoint", None)        self.add_url_rule(rule, endpoint, f, **options)        return f    return decorator#可以不使用装饰器的方式 注册路由app.add_url_rule("/", endpoint=None, view_func=home, methods=["GET"])    #flask路由的本质是app对象的add_url_rule完成路由的注册

5.2路由参数 add_url_rule

ruleURL规则
view_func视图函数名称
defaults=None默认值 当URL中没有参数 函数需要参数时 使用defaults={"k":"v"}为函数提供参数
endpoint = None路径的别名 用于反向解析URL 即: url_for("名称")
methods=None允许的请求方式 如:["GET", "POST"]
# 对URL最后的/符号是否严格要求strict_slashes = None    """        @app.route("/index", strict_slashes=False)        #访问http://www.xx.com/index/ 或http://www.xx.com/index均可        @app.route("/index", strict_slashes=True)        #仅访问http://www.xx.com/index    """    # 重定向到指定位置redirect_to = None,     """        @app.route("/index/", redirect_to="/home/")    """

5.3 转换器

"default":UnicodeConverter
"string":UnicodeConverter
"any":AnyConverter
"path":PathConverter
"int":IntegerConverter
"float":FloatConverter
"uuid":UUIDConverter

了解:让路由支持正则

6.cbv分析

#基于类的视图 写法from  flask import Flask,requestfrom flask.views import View,MethodViewapp = Flask(__name__)app.debug = True#视图类 继承MethodView 类中写跟请求方式同名的方法即可 跟之前学的所有都一致class IndexView(MethodView):    def get(self):        print(request.method)        return "get请求"    def post(self):        print(request.method)        return "post请求"app.add_url_rule("/index",endpoint="index",view_func=IndexView.as_view("index"))if __name__ == "__main__":    app.run()

6.1 源码分析

# 1 IndexView.as_view("index") 执行完的结果,是个函数(view的)内存地址    def as_view(cls, name, *class_args, **class_kwargs):        def view(**kwargs: t.Any) -> ft.ResponseReturnValue:            # 本质是在执行self.dispatch_request,只是用了异步           return current_app.ensure_sync(self.dispatch_request)(**kwargs)        return view        # 2 请求来了,执行view()--->本质在执行self.dispatch_request---》MethodView中的    def dispatch_request(self, **kwargs):        # self是视图类的对象        meth = getattr(self, request.method.lower(), None)        # 用异步执行meth()        return current_app.ensure_sync(meth)(**kwargs)        # 3 总结:执行原理跟django一样# 4 路径如果不传别名,别名就是函数名---》分析一下源码-@app.route("/index")--》没有传endpoint    -endpoint 就是None---》调用了app.add_url_rule,传入了None    if endpoint is None:       endpoint = _endpoint_from_view_func(view_func)  # type: ignore-_endpoint_from_view_func 就是返回函数的名字# 5 as_view("index") 必须传参数,传进来的参数是,是【别名】# view是as_view内的内层函数,闭包函数view.__name__ = name  # 修改了函数的名字变成了你传入的        # app.add_url_rule("/index",view_func=IndexView.as_view("index"))    简写成:app.add_url_rule("/index",view_func=view)    #如果不传参数, 所有人的别名(endpoint),都是内层函数view,所以就报错了           #6 补充:flask的路由注册使用装饰器,如果写了一个登录认证装饰器,那么应该放在路由装饰器上还是下?-放在路由下面    -路由必须传endpoint,如果不传,又报错        #7  视图类必须继承MethodView,如果继承View,它的dispatch_request没有具体实现,你的视图类必须重写dispatch_request,我们不想重写,继承MethodView    def dispatch_request(self) -> ft.ResponseReturnValue:        raise NotImplementedError()        # 8 视图类加装饰器,直接配置在类属性上【decorators】即可decorators = [auth,]    # 源码,cls是视图类,中有decorators    if cls.decorators:      for decorator in cls.decorators:          view = decorator(view)  # view=auth(view)-1 as_view 执行流程跟djagno一样    -2 路径如果不传别名,别名就是函数名(endpoint)    -3 视图函数加多个装饰器(上下顺序和必须传endpoint)    -4 视图类必须继承MethodView,否则需要重写dispatch_request    -5 视图类加装饰器:类属性decorators = [auth,]    

7.模板

7.1py文件

from flask import Flask, render_template,Markupapp = Flask(__name__, template_folder="templates", static_folder="static")  # 模板的路径必须是templates,因为实例化app对象时,传入的app.debug=Truedef add(a,b):    return a+b@app.route("/")def index():    a="点我看美女"  # 不存在xss攻击,处理了xss    a=Markup(a)    return render_template("index.html",name="lqz",a=a,add=add)if __name__ == "__main__":    app.run()

7.2 index.html

        Title

模板语法,static

模板语法,if

{% if name %}

Hello {{ name }}!

{% else %}

Hello World!

{% endif %}

模板语法,标签渲染

{{a"safe}}{{a}}

模板语法,执行函数

{{add(4,5)}}

8.请求与响应

请求:全局的request对象响应:四件套
request.method提交的方法
request.argsget请求提交的数据
request.formpost请求提交的数据
request.valuespost和get提交的数据总和
request.cookies客户端所带的cookie
request.headers请求头
request.path不带域名 请求路径
request.full_path不带域名 带参数的请求路径
request.script_root
request.url待域名带参数的请求路径
request.base_url待域名请求路径
request.url_root域名
request.host_url域名
request_host127.0.0.1:500
### 响应  四件套    # 1 响应中写入cookie    # response = "hello"    # res = make_response(response)  # flask.wrappers.Response    # print(type(res))    # res.set_cookie("xx","xx")    # return res    # 2 响应头中写数据(新手四件套,都用make_response包一下)    response = render_template("index.html")    res = make_response(response)  # flask.wrappers.Response    print(type(res))    res.headers["yy"]="yy"    return res

9.session济源吗分析

9.1 session的使用说明

# cookie :存在于客户端浏览器的键值对# session:存在于服务端的键值对    # djagno 放在了django_session表中# flask中,叫session,问题来了,存哪里了?-加密后,放到了cookie中,如果session发生了变化,我们的cookie也会跟着变        # 源码部分:# 1 app.session_interface  配置了一个类的对象,这个就是session的执行流程    # 2 类中有两个非常重要的方法,请求来了,会执行open_session,请求走了会执行save_session      def open_session(self, app, request) :#1 根据名字,取出前端传入的cookie的value值        val = request.cookies.get(self.get_cookie_name(app))        #2 如果没有val,构造了一个空session对象        if not val:            return self.session_class()        max_age = int(app.permanent_session_lifetime.total_seconds())        try:            # 如果没有过期,解码,做成session对象,后续直接用session即可            data = s.loads(val, max_age=max_age)            return self.session_class(data)        except BadSignature:            # 如果过期了,也是空session            return self.session_class()                    def save_session(self, app, session, response) :        name = self.get_cookie_name(app)# 取出过期事件,和把session加密转成字符串,放到cookie中        expires = self.get_expiration_time(app, session)        val = self.get_signing_serializer(app).dumps(dict(session))        response.set_cookie(            name,            val,             expires=expires,        )                                  # 扩展,想把session放到redis中,mysql中,已经有人帮咱们写了,第三方的只需要写个类,重写open_session,save_session自己写

10.闪现

flash 翻译过来的当次请求先把一些数据 放在某个位置    下一次请求 把这些数据取出来 取完 就没了    作用:1.可以跨请求 来保存数据    2.当次请求 访问出错 被重定向到其他地址 重定向到这个地址后 拿到当时的错误    django中有这个东西吗message框架    用法:设置 闪现    flash("%s sorry" % name) 可以设置多次 放到列表中        flash("超时错误",category="debug")分类存    获取 闪现    get_flashed_messages() ,取完就删除        get_flashed_messages(category_filter=["debug"])分类取本质:放到session中

11.请求扩展

请求扩展中:在请求来了,或请求走了,可以绑定一些函数,到这里就会执行这个函数,类似于django的中间件在flask中就用请求扩展,来代替djagno的中
before_request请求来了会走,如果他返回了四件套,就结束了
after_request请求走了会走,一定要返回response对象
before_first_request第一次来了会走
teardown_request无论是否出异常,会走
errorhandler监听状态码,404 500
template_global标签
template_filter过滤器
from flask import Flask, request,render_templateapp = Flask(__name__)####1 before_request 和 after_request# 请求来了,执行一个函数,来的时候从上往下执行# @app.before_request# def before():#     print("我来了111")#     # if "index" in request.path:#     return "不让看了"  # 如果不是retrun了None,说明被拦截了,直接返回### @app.before_request# def before1():#     print("我来了222")### # 请求走了,执行一个函数,走的时候,从下往上执行# @app.after_request# def after(response):#     print("我走了111")#     return response### @app.after_request# def after2(response):#     print("我走了222")#     return response# 2 项目启动后的第一个请求# @app.before_first_request# def first():#     print("我的第一次")# 3 teardown_request,无论视图函数是否出错,都会执行它,做错误日志# @app.teardown_request# def teardown(e):#     print(e)#     print("执行我了")# 4 errorhandler  监听响应状态码,如果符合监听的状态码,就会走它# @app.errorhandler(404)# def error_404(arg):#     return "404错误了"# @app.errorhandler(500)# def error_500(arg):#     return "500错误了"##5 template_global  在模板中直接使用该过滤器@app.template_global()def add(a1, a2):    return a1 + a2# 6 template_filter@app.template_filter()def db(a1, a2, a3):    return a1 + a2 + a3@app.route("/")def index():    # a = [1, 2, 3]    # print(a[9])    return render_template("index1.html")if __name__ == "__main__":    app.run()

关键词: