flask快速上手

1 flask 介绍

# python 界的web框架
	-Django:大而全,快速开发,公司内部项目
    -Flask:小而精,不具备web开发好多功能,丰富的第三方插件
    -FastApi:异步框架,主要为了做前后端分离接口
    -Sanic:异步框架,只支持python3.6 及以上,性能比较高
    -Tornado:公司用的比较少。。。
    
# Flask 框架
	-pip3 install flask
    

fastapi

import time
from fastapi import FastAPI
app = FastAPI()
@app.get('/')
async def index():
    time.sleep(3)
    return {'code': 100, 'msg': '成功'}

@app.get('/home')
async def home():
    time.sleep(2)
    return {'code': 100, 'msg': 'home'}

@app.get('/order')
async def home():
    time.sleep(2)
    return {'code': 100, 'msg': 'order'}


flask

from flask import Flask
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index():
    return 'hello world'
if __name__ == '__main__':
    app.run()

wsgiref

# 服务 wsgi协议的web服务器,django的web服务用的就是它
# 相当于个socket服务端,可以接收客户端发送过来的请求,处理,返回给客户端


from wsgiref.simple_server import make_server

def mya(environ, start_response):
    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]

if __name__ == '__main__':
    myserver = make_server('', 8011, mya)# 监听本地的8011端口,当请求来了,就会执行    mya(),传入两个参数,一个是environ:http请求转成python的字典,一个是start_response:响应对象
    print('监听8010')
    myserver.serve_forever()



image

Werkzeug

Werkzeug是一个WSGI工具包(在它基础上,继续封装),他可以作为一个Web框架的底层库。这里稍微说一下, werkzeug 不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web 框架的底层库,因为它封装好了很多 Web 框架的东西,例如 Request,Response 等等

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)

image

2 显示用户小案例

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

app = Flask(__name__, template_folder='templates')
app.debug = True
app.secret_key = 'sdfsdfsdfsdf'  # 等同于django的 配置文件有个很长的秘钥


USERS = {
    1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
    2:{'name':'李四','age':28,'gender':'男','text':"安全第一条"},
    3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}



@app.route('/login', methods=['GET', 'POST'])
def login():
    # 只要在这个函数中,全局的request 就是当次请求的request对象,等同于django的request
    if request.method == 'GET':  # get请求返回模板
        return render_template('login.html')  # 新手四件套之一,返回模板
    else:
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'lqz' and password == '123':
            # 登录成功,把登录信息,写入到session中
            session['username'] = username
            # return redirect('http://www.baidu.com')   #重定向到百度,新手四件套之一,返回重定向
            return redirect('/index')  # 重定向到百度,新手四件套之一,返回重定向
        else:
            return render_template('login.html', error='用户名或密码错误')


@app.route('/index')
def index():
    # 判断它是否登录,如果登录,显示用户信息
    if session.get('username'):
        return render_template('index.html',users=USERS)
    else:
        return redirect('/login')



@app.route('/detail/<int:pk>')
def detail(pk):
    user=USERS.get(pk)
    return render_template('detail.html',user=user)

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



'''
1 新手三件套: 1 直接返回字符串  2 render_template  3 redirect
2 flask的路由写法,是基于装饰器的  @app.route('/detail/<int:pk>' ,methods=['GET'])
3 路由转换器跟django一样
4 取出前端post请求提交的数据:request.form
5 取出请求方式:request.method
6 使用session设置值和取值   
    -session[key]=value
    -session.get('key')
7 flask的模板语法完全兼容dtl,并且它更强大,可以加括号执行

'''

detail.html

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

</head>
<body>
<h1>详细信息 {{user.name}}</h1>
    <div>
        {{user.text}}
    </div>

</body>
</html>

index.html

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

</head>
<body>
<h1>用户列表</h1>
<table>
    {% for k,v in users.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>

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="" method="post">
    <p>用户名:<input type="text" name="username"></p>
    <p>密码:<input type="password" name="password"></p>
    <p><input type="submit" value="提交">{{error}}</p>

</form>


</body>
</html>

3.登录认证装饰器

# 1 装饰器的本质原理
	-# 类装饰器:1 装饰类的装饰器   2 类作为装饰器
# 2 装饰器使用位置,顺序
# 3 flask路由下加装饰器,一定要加endpoint
	-如果不指定endpoint,反向解析的名字都是函数名,不加装饰器没有问题,就是正常函数index,detail
    -如果加了装饰器---》index,detail都变成了inner---》反向解析的名字都是函数名inner,报错了
    -wrapper装饰器----》把它包的更像---》函数名变成了原来函数的函数名
# 装饰器:是什么? 装饰器的本质是闭包【函数】
# 装饰器:作用? 在不改变程序源代码和调用方式的基础上,为程序增加新功能
# 装饰器:本质,被装饰以后,在执行被装饰的函数,其实执行不是之前的函数了,所有才加入了新功能
# 装饰器:语法糖  @    python的特殊语法,它有特殊作用----》把被装饰的函数(装饰器下面的函数),当参数传入装饰器,并把装饰器的执行结果赋值给被装饰的函数
def add(func):
    print(func)


# 类装饰器:1 装饰类的装饰器   2 类作为装饰器

# add 一定是个函数吗?
# 放个对象
class Person:
    def __call__(self, func):
        def inner(*args, **kwargs):

            res = func(*args, **kwargs)
            return res
        return inner

p = Person()

# @add  # test=add(test)--->test变成了None
@p  # test=p(test)  # p() 会触发__call__--->Person的 __call__(func)--->返回inner,以后test就是inner---》test(参数)--》执行的是inner
def test():
    print("test")

print(test)

def auth(func):
    def inner(*args, **kwargs):
        res = func(*args, **kwargs)  # 真正的执行视图函数,执行视图函数之,判断是否登录
        res.name='lqz'
        return res
    return inner

@auth     # Foo=auth(Foo)
class Foo():
    pass

f=Foo()  # Foo()  调用 ---》inner()--->类实例化得到对象,返回,以后f就是Foo的对象,但是可以里面多了属性或方法
print(f)
print(f.name)



### 有参装饰器--->额外为被装饰的函数传参数
@auth(10)     # Foo=auth(10)(Foo)
class Foo():
    pass

4、配置文件

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

app = Flask(__name__)
# flask的所有配置都放在app中了,以后直接使用app对象,获取配置信息即可

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

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


@app.route('/login', methods=['GET', 'POST'])
def index():
    return 'hello web'

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

5 路由系统

5.1 路由本质

# django中配置路由 在urls.py 中,写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>')
    '''
    
    
 # 需要记住的
    # rule  
    # view_func   
    # defaults
    # endpoint
    # methods

5.3 转换器

 'default':          UnicodeConverter,
 'string':           UnicodeConverter,
 'any':              AnyConverter,
 'path':             PathConverter,
 'int':              IntegerConverter,
 'float':            FloatConverter,
 'uuid':             UUIDConverter,
    
 # 了解:让路由支持正则(忽略掉)
posted @ 2023-07-31 19:51  岳宗柯  阅读(40)  评论(0编辑  收藏  举报