flask框架01 flask与pythonweb框架介绍 flask快速使用 登录显示用户信息案列 配置文件方式 路由系统

发布时间 2023-04-04 21:12:33作者: 小白峰

今日内容详细

1 Flask 和pythonweb框架介绍

python web框架的本质都一样
1.同步框架
	django 大而全 内置的app多 第三方app也多
	flask 小而精 没有过多的内置组件 只完成web框架最基本的功能 需要借助于第三方来完成更加丰富的功能
	web.py 是一个小巧灵活的python框架 它简单且功能强大 但国内很少使用
2.异步框架
	fastapi python的异步web框架 不少公司在使用 https://fastapi.tiangolo.com/zh/
	sanic Python的异步web框架 供支持异步高并发请求的web服务
	tornado 异步框架 用到比较少了
 
同步框架和异步框架的区别
	同步框架的意思:一个线程只处理一个请求
	异步框架的意思:一个线程可以处理多个请求
	异步框架可以很显著的提高并发量
 
django在3.x后就支持异步了 所以即是同步框架也是异步框架

1.1 flask介绍

flask是一个基于python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架
	jinja2 模板语法 和django的dtl非常的像 但是比它强大
	Werkzeug WSGI 符合wsgi协议的web服务器 django中使用的wsgiref
 
小案例:wsgiref写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 word')
 
 
if __name__ == '__main__':
    from werkzeug.serving import run_simple
    run_simple('localhost', 4000, hello)

2 flask快速使用

安装:pip install flask
 
安装最新的就行 2.x相比1.x虽然源代码动了 但是没有区别
 
from flask import Flask
 
# 实例化得到对象 传入一个任意字符串
app = Flask(__name__)
 
 
# 通过装饰器注册路由
@app.route('/')
def home():
    return 'hello word'
 
 
if __name__ == '__main__':
    # 启动 不传参数默认127.0.0.1 5000端口
    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>
    <p><input type="submit" value="登陆"></p>{{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.3 detail.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, render_template, request, session, redirect, jsonify
 
# 实例化得到对象 传入一个任意字符串
app = Flask(__name__)
 
app.debug = True
app.secret_key = 'woefosngajsoidfjajwenfa'
 
USERS = {
    1:{'name':'张三','age':18,'gender':'男','text':"道路千万条"},
    2:{'name':'李四','age':28,'gender':'男','text':"安全第一条"},
    3:{'name':'王五','age':18,'gender':'女','text':"行车不规范"},
}
 
 
# 通过装饰器注册路由
@app.route('/home')
def home():
    if not session.get('user'):
        return redirect('/login')
    return render_template('home.html', user_dict=USERS)
 
# 添加转换器 可以接受参数
@app.route('/detail/<int:pk>')
# 路由中转换器名是啥就接收啥
def detail(pk):
    # session中没有user说明没登陆 直接跳转到登陆界面
    if not session.get('user'):
        return redirect('/login')
    user = USERS.get(pk)
    return render_template('detail.html', user=user)
 
# 既可以通过传methods参数可以指定接受哪些请求
@app.route('/login', methods=['get', 'post'])
def login():
    # request对象需要导入  post请求再进行逻辑判断
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        if username == 'lzj' and password == '123':
            # 验证通过 存入session中 是模块 需要导入
            session['user'] = username
            return redirect('/home')
        # 前后端混合 可以直接以位置参数的形式将页面需要的参数传递给页面
        return render_template('login.html', error='用户名或密码错误')
    return render_template('login.html')
 
 
@app.route('/test')
def test():
    # 返回json格式 只能传字典和列表
    return jsonify([{'name':'lzj','age':19}])
 
 
if __name__ == '__main__':
    # 启动
    app.run()
 
 
'''
总结
	1.注册路由
		app.route(路径,methods=[请求方式1,请求方式2])
	2.新手四件套
		render_template  返回页面 并且可以传值 和django有区别
		redirect		重定向
		return 字符串 		直接返回字符串
		jsonify			返回json格式
	3.请求的request对象 是全局的 导入使用即可 但是在不同视图函数中并不会混乱 都是自己的
		request.from  请求体中的内容转换成字典放在这
		request.method  请求方式
	4.session是全局的 也是导入使用即可 一定要指定秘钥
		app.secret_key = '秘钥串'
		session[''] = '' 放值
		session.get()   取值
	5.模板的渲染
		兼容django的dtl语法 但更强大 可以加括号 字典也可以通过.values() .items()取值
	6.转换器
		@app.route('/路由/<int:pk>')
 
'''

4 配置文件方式

flask中的配置文件是一个flask.config.Config对象(继承字典),默认配置为:
 {
        'DEBUG':                                get_debug_flag(default=False),  是否开启Debug模式
        'TESTING':                              False,                          是否开启测试模式
        'PROPAGATE_EXCEPTIONS':                 None,                          
        'PRESERVE_CONTEXT_ON_EXCEPTION':        None,
        'SECRET_KEY':                           None,
        'PERMANENT_SESSION_LIFETIME':           timedelta(days=31),
        'USE_X_SENDFILE':                       False,
        'LOGGER_NAME':                          None,
        'LOGGER_HANDLER_POLICY':               'always',
        'SERVER_NAME':                          None,
        'APPLICATION_ROOT':                     None,
        'SESSION_COOKIE_NAME':                  'session',
        'SESSION_COOKIE_DOMAIN':                None,
        'SESSION_COOKIE_PATH':                  None,
        'SESSION_COOKIE_HTTPONLY':              True,
        'SESSION_COOKIE_SECURE':                False,
        'SESSION_REFRESH_EACH_REQUEST':         True,
        'MAX_CONTENT_LENGTH':                   None,
        'SEND_FILE_MAX_AGE_DEFAULT':            timedelta(hours=12),
        'TRAP_BAD_REQUEST_ERRORS':              False,
        'TRAP_HTTP_EXCEPTIONS':                 False,
        'EXPLAIN_TEMPLATE_LOADING':             False,
        'PREFERRED_URL_SCHEME':                 'http',
        'JSON_AS_ASCII':                        True,
        'JSON_SORT_KEYS':                       True,
        'JSONIFY_PRETTYPRINT_REGULAR':          True,
        'JSONIFY_MIMETYPE':                     'application/json',
        'TEMPLATES_AUTO_RELOAD':                None,
    }

方式一:
	app.debug = True # 调试模式 提示的信息更加详细 修改代码不需要重启 会自动重启
	app.secret_key = '' # 给session设置秘钥
	该方式只能设置debug和secret_key
方式二:
	app.config['DEBUG'] = True
	app.config['SECRET_KEY'] = ''
	通过app.config设置 是一个字典 key值必须是大写
方式三:
	app.config.from_pyfile('settings.py')
	通过引入设置文件 并且变量名都为大写 不常用
方式四:
	 class BASE(object):
        DEBUG = False
 
    class ProductionConfig(BASE):
        DATABASE_URI = 'mysql://user@localhost/foo'
 
    class DevelopmentConfig(BASE):
       DEBUG = True
       DATABASE_URI = 'localhost'
        
	app.config.from_object('DevalopmentConfig')
   app.config.from_object('DevalopmentConfig')
	通过引入类的方式 常用它 无需使用多个py文件管理多套配置
方式五:
	app.config.from_envvar('环境变量名')
	通过环境变量配置
方式六:
	app.config.from_json('json文件名称')
	必须是要是json格式 因为内部会执行json.loads
方式七:
	app.config.from_mapping({'DEBUG':True})
	通过字典的形式 

5 路由系统

django中配置路由是在urls.py中来实现
flask是基于装饰器的 大部分都是通过装饰器来实现 也可以少部分抽取到py文件中
 
路由装饰器源码分析
@app.route('/login')
def login():
    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
查看route函数
    @setupmethod # 没见过 先不关注 rule就是传进来的/login options是多余的参数
    def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: # rule:str 表示该参数接收字符串类型 ->表示返回的类型 其他同理
        # f就是被装饰的函数 也就是login函数
        def decorator(f: T_route) -> T_route:
            # endpoint我们并没有传 也就是None 先忽略
            endpoint = options.pop("endpoint", None)
            # 真正的添加路由函数 查看源码发现self就是app对象
            self.add_url_rule(rule, endpoint, f, **options)
            return f
        return decorator
 
查看源码发现真正添加路由的是add_url_rule函数 那么我们也可以手动添加
 
def home():
    pass
 
app.add_url_rule('/', endpoint=None, view_func=home, methods=['GET'])
和django的添加路由有点相似
 
add_url_rule中的参数
	rule			url规则
	view_func		视图函数名
	defaults=None	默认值 当url中不需要参数 但是函数需要时可以使用 defaults={k:v}
	endpoint=None	路由的别名 用于反向解析url
	methods=Node	允许请求的方式 如['GET','POST']
	strict_slashes=None	对url中最后的'/'是否严格要求
	redirect_to=None	重定向到指定的地址

5.1转换器

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