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 就等同于django
def 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'<h1>Hello, web!</h1>'
    return [data]  # 做成了response

if __name__ == '__main__':
    myserver = make_server('', 8008, mya)
    print('监听8010')
    myserver.serve_forever()
    
#使用werkzeug写web
from werkzeug.wrappers import Request, Response


@Request.application
def 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 Flask

app = 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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<form method="post">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="password" name="password"></p>
    <input type="submit" value="登录"> {{error}}
</form>
</body>
</html>

3.2 home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<table>
    {% for k,v in user_dict.items() %}
    <tr>
        <td>{{k}}</td>
        <td>{{v.name}}</td>
        <td>{{v['name']}}</td>
        <td>{{v.get('name')}}</td>
        <td><a href="/detail/{{k}}">查看详细</a></td>
    </tr>
    {% endfor %}
</table>
</body>
</html>

3.3detail.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<p>名字是:{{user.name}}</p>
<p>年龄是:{{user['age']}}</p>
<p>性别是:{{user.get('gender')}}</p>
<p>{{user.text}}</p>


</body>
</html>

3.4 py文件

from flask import Flask, request, render_template, redirect, session,jsonify

app = 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/<int:pk>')
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/<int:pk>')

'''

配置文件方式

# django 在settings配置

# flask也有配置问题 但是他的方式有多种:

设置的方式一:测试用
app.debug = True					   #调试模式 提示信息更详细 修改代码不需要重启 自动重启
app.secret_key = 'fglqagvuivefew35few' #密钥 只能放debug和secret_key

设置方式二:直接使用app.config设置
app.config['DEBUG']=True
app.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

rule URL规则
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/<int:nid>', redirect_to='/home/<nid>')
    '''

5.3 转换器

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

了解:让路由支持正则

6.cbv分析

#基于类的视图 写法

from  flask import Flask,request
from flask.views import View,MethodView


app = 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,Markup

app = Flask(__name__, template_folder='templates', static_folder='static')  # 模板的路径必须是templates,因为实例化app对象时,传入的
app.debug=True


def add(a,b):
    return a+b
@app.route('/')
def index():
    a='<a href="http://www.baidu.com">点我看美女</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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>模板语法,static</h1>
<img src="/static/1.jpg" alt="">

<h1>模板语法,if</h1>
{% if name %}
<h1>Hello {{ name }}!</h1>
{% else %}
<h1>Hello World!</h1>
{% endif %}

<h1>模板语法,标签渲染</h1>
{{a|safe}}
{{a}}

<h1>模板语法,执行函数</h1>
{{add(4,5)}}

</body>
</html>

8.请求与响应

请求:全局的request对象
响应:四件套
request.method 提交的方法
request.args get请求提交的数据
request.form post请求提交的数据
request.values post和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_host 127.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_template

app = 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()


posted @ 2023-04-03 21:21  李李大冒险  阅读(54)  评论(0编辑  收藏  举报
  1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 迷人的危险3 FAFA
  4. 4 山楂树之恋 程佳佳
  5. 5 summertime cinnamons / evening cinema
  6. 6 不谓侠(Cover 萧忆情Alex) CRITTY
  7. 7 神武醉相思(翻自 优我女团) 双笙(陈元汐)
  8. 8 空山新雨后 音阙诗听 / 锦零
  9. 9 Wonderful U (Demo Version) AGA
  10. 10 广寒宫 丸子呦
  11. 11 陪我看日出 回音哥
  12. 12 春夏秋冬的你 王宇良
  13. 13 世界が终わるまでは… WANDS
  14. 14 多想在平庸的生活拥抱你 隔壁老樊
  15. 15 千禧 徐秉龙
  16. 16 我的一个道姑朋友 双笙(陈元汐)
  17. 17 大鱼 (Cover 周深) 双笙(陈元汐)
  18. 18 霜雪千年(Cover 洛天依 / 乐正绫) 双笙(陈元汐) / 封茗囧菌
  19. 19 云烟成雨(翻自 房东的猫) 周玥
  20. 20 情深深雨濛濛 杨胖雨
  21. 21 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  22. 22 斑马斑马 房东的猫
  23. 23 See You Again Wiz Khalifa / Charlie Puth
  24. 24 Faded Alan Walker
  25. 25 Natural J.Fla
  26. 26 New Soul Vox Angeli
  27. 27 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  28. 28 像鱼 王贰浪
  29. 29 Bye Bye Bye Lovestoned
  30. 30 Blame You 眠 / Lopu$
  31. 31 Believer J.Fla
  32. 32 书信 戴羽彤
  33. 33 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  34. 34 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  35. 35 慢慢喜欢你 LIve版 戴羽彤
  36. 36 病变 戴羽彤
  37. 37 那女孩对我说 (完整版) Uu
  38. 38 绿色 陈雪凝
  39. 39 月牙湾 LIve版 戴羽彤
像鱼 - 王贰浪
00:00 / 04:45
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 周有才

作曲 : 周有才

这是一首简单的歌

没有什么独特

试着代入我的心事

它那么幼稚

像个顽皮的孩子

多么可笑的心事

只剩我还在坚持

谁能看透我的眼睛

让我能够不再失明

我要记住你的样子

像鱼记住水的拥抱

像云在天空中停靠

夜晚的来到

也不会忘了阳光的温暖

我要忘了你的样子

像鱼忘了海的味道

放下所有梦和烦恼

却放不下回忆的乞讨

多么可笑的心事

只剩我还在坚持

谁能看透我的眼睛

让我能够不再失明

记住你的样子

像鱼记住水的拥抱

像云在天空中停靠

夜晚的来到

也不会忘了阳光的温暖

我要忘了你的样子

像鱼忘了海的味道

放下所有梦和烦恼

却放不下回忆的乞讨

只剩自己就好