web框架介绍与flask简介,快速使用flask
python web框架介绍
python主流的web框架
django
大而全,内置的app多,第三方也多
flask
小而精,没有很多的内置组件,只完成web框架最基本的功能,需要借助于第三方来完成更丰富的功能。 适合快速开发
web.py
python一个小巧灵活的框架。简单且功能强大
异步的web框架
fastapi
python的异步框架,很多公司都在使用.与flask的区别在于异步编写不一样用的挺多
官方网站 https://fastapi.tiangolo.com/zh/
sanic
python的异步框架,支持异步高并发请求的 web 服务
tornado
异步框架。基本上不怎么用了。
同步框架与异步框架的区别
同步框架: 一个线程只处理一个请求
异步框架: 一个线程可以处理多个请求
异步框架可以提高并发量
flask介绍
flask
是一个基于python开发并依赖jinja2
模板和werkzeug WSGI
服务的一个微型框架
jinja2
模板语法,与django的dtl非常像
werkzeug WSGI
符合wsgi协议的web服务器比django的web服务器封装了更多的东西,django使用的是wsgiref。
# 1. 使用wsgiref编写web
from wsgiref.simple_server import make_server
# mya 就等同于django只不过django在这里面把environ包装成了request
def mya(environ, start_response):
#environ 字典,请求里的东西
print(environ)
# 响应
start_response('200 OK', [('Content-Type', 'text/html')])
# 在request里是path environ是past_info
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] # django在这里做成了response
if __name__ == '__main__':
myserver = make_server('', 8008, mya)
print('监听8010')
myserver.serve_forever()
# 2 使用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)
快速使用
安装
pip install flask
1.x 版本之间没有本质上的区别
2.x 源码上动了,用起来和原本用法一样
会自动安装依赖 MarkupSafe, Werkzeug, Jinja2, flask
快速写一个flask
from flask import Flask
# 实例化得到一个Flask对象
app = Flask(__name__)
# 注册路由,使用装饰器 login函数,访问/login会执行
@app.route('/login')
def login():
return '啦啦啦'
@app.route('/')
def home():
return 'home'
# 启动必须写的
if __name__ == '__main__':
# 0.0.0.0 监听本地ip地址,局域网内都可以访问
app.run()
# 访问http://127.0.0.1:5000/login 会返回啦啦啦
flask写登录
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post">
<!--写一个登录表单-->
<input type="text" name='username' placeholder="请输入用户名">
<!--密码表单-->
<input type="password" name="password" placeholder="请输入密码">
<!--写一个登录按钮-->
<input type="submit" value="登录"> {{error}}
</form>
</body>
</html>
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>
detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>用户名:{{user_detail.name}}</p>
<p>年 龄:{{user_detail['age']}}</p>
<p>性 别:{{user_detail.get('gender')}}</p>
<p>详 情:{{user_detail.get('text')}}</p>
</body>
</html>
功能py文件
from flask import Flask, request, render_template, redirect, session,jsonify
app = Flask(__name__)
# 想要使用session,需要设置secret_key
app.secret_key = '21312dsadg12'
# 造一个users字典
users = {
1: {'name': 'lxj', 'age': 18, 'gender': '男', 'text': '我是lxj'},
2: {'name': 'zyg', 'age': 68, 'gender': '不明', 'text': '我是zyg'}
}
# 需要返回一个页面,创建一个templates文件夹,里面创建一个login.html
@app.route('/login', methods=['GET', 'POST']) # 默认只能接收get请求,如果需要接收post请求,需要指定methods=['GET','POST']
def login():
# get请求返回模板,没有request对象,需要导入全局request对象,每个视图函数都会有一个自己的request对象
if request.method == 'GET':
# 新手四件套之一,返回模板reder_template ,需要导入
return render_template('login.html')
else:
# post请求处理校验数据
# 获取用户名和密码,从form里取,等同于django的request.POST
username = request.form.get('username')
password = request.form.get('password')
# 校验数据
if username == 'lxj' and password == '123':
# 登录成功(需要保存登录状态),新手四件套之一,重定向redirect
# 保存到session中,也需要导入全局,也是每个视图函数都会有一个自己的session,需要设置secret_key不然报错
session['name'] = username
return redirect('/')
else:
# 登录失败,返回模板,并且需要传递错误信息
return render_template('login.html', error='用户名或密码错误')
@app.route('/')
def home():
# 登录成功才能访问首页,不成功就重定向到登录页面
# 从session中获取登录状态
name = session.get('name')
if name:
return render_template('home.html', user_dict=users)
else:
return redirect('/login')
@app.route('/detail/<int:id>')
def detail(id):
# 校验是否登录
name = session.get('name')
if not name:
return redirect('/login')
user_detail=users.get(id)
return render_template('detail.html',user_detail=user_detail)
@app.route('/test')
def test():
# 返回json示例
return jsonify({'name':'lxj','age':18})
if __name__ == '__main__':
app.run()
总结
"""
总结:
注册路由 app.route(路径,menhods=['GET','POST'])
1.获取数据与请求方式: 需要导入request
request.method 取请求方式
request.form 取数据
2.返回页面: 需要创建一个templates文件夹,编写html文件
3.保存登录状态: 需要导入session,需要设置secret_key
session['key']=value 存储到session中
session.get('key') 从session中取值
4.模板渲染
-兼容django的dtl
-更强大,可以加括号,字典可以. | get | [] .values() .items()
-{% for %}
5.路由可以加转换器 <int:id>
新式四件套:
1.返回模板 导入render_template
2.重定向 导入redirect
3.返回字符串 直接return
4.返回json 导入jsonify
"""
配置文件
在django
中有settings
,任何项目都会有配置文件,使用方式不同。
flask
也有配置文件
1.测试阶段
from flask import Flask
app = Flask(__name__)
# flask所有的配置都放在app里,直接使用app对象获取配置信息
# 1.设置方式一
# app.debug= True # 调试模式, 修改代码后不需要重启服务器,自动重启 提示错误信息更详细
# app.secret_key='213jdfssd11' # 设置session的密钥
# "都放在了app.config里"
# 2.设置方式二
# app.config['DEBUG']=True
# app.config['secret_key'] = '213jdfssd11'
# 3. 使用py文件
app.config.from_pyfile('settings.py') #创建一个py文件,在里面修改
# 4. 常用的,类的方式,在settings里写3个类,开发用,测试用,上线用
app.config.from_object('settings.Development') # 指定文件里的类
"""
settings.py内
class BASE(object):
DEBUG = False
class Production(BASE):
DATABASE_URI = 'mysql://user@localhost/foo'
class Development(BASE):
DEBUG = True
DATABASE_URI = 'localhost'
"""
@app.route('/')
def home():
return 'hello world'
if __name__ == '__main__':
app.run()
其他方法
### 其他:
#通过环境变量配置
# app.config.from_envvar("环境变量名称")
# json
# app.config.from_json("json文件名称")
# JSON文件名称,必须是json格式,因为内部会执行json.loads
# 字典格式---》配置中心
# app.config.from_mapping({'DEBUG': True})
内置的配置字段
常用的
DEBUG
SECRET_KEY
SESSION_COOKIE_NAME # 网页cookie里session的名字
PERMANENT_SESSION_LIFETIME # session过期时间设置
其他的可以自己写
eg:
redis的链接地址
mysql的链接地址
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,
}
路由系统
flask
的路由是基于装饰器的(用的多),也可以写在py文件里。
回顾装饰器:
装饰器是什么?
装饰器的本质是闭包函数。被装饰以后。在执行被装饰的函数其实不是执行之前的函数了,执行的是装饰器返回的函数。所以才加入新的功能。
它的作用是在不改变程序原代码和调用方式的基础上为程序增加新功能。
本质是通过闭包函数实现。
装饰器语法糖 就是@
python的特殊语法。它有特殊作用 --把被装饰函数当做参数传入装饰器。并把把装饰器的执行结果赋值给 被装饰的函数。
app.route源码分析
# 路由的装饰器源码分析
# 咱们这样写
@app.route('/login')
def index():
pass
1.本质是 index = app.route('/login')(index)
2.app.route('/login')执行结果return了decorator函数
3 等于执行了 decorator(index)
def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]:
"""
rule 是路径
options 接收了其他参数
"""
def decorator(f: T_route) -> T_route:
"f 就是被装饰器当做参数传进来的index"
endpoint = options.pop("endpoint", None) #options相当于一个字典,现在没有endpoint参数,那么endpoint = None
# 核心 self就是app=flask(__name__)实例化得到的对象(flask对象),(flask继承了Scaffold)
# 对象里有个方法add_url_rule,就是在添加路由
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
不使用装饰器 自己注册路由的方法就是用app对象调用add_url_rule方法
app.add_url_rule('/',endpoint=None,view_func=home,methods=['GET'])
其实add_url_rule 类似 django中的path
flask
路由的本质其实就是用app对象的add_url_rule 方法完成路由注册
add_url_rule参数
重要
rule # URL 路由规则(路径)
view_func # 视图函数
defaults=None # 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}为函数提供参数
endpoint=None, # 路径的别名,名称,用于反向解析URL,和django路由注册中的name一样
methods=None # 允许的请求方式,如:["GET", "POST"]
了解
strict_slashes = None #对URL最后的 / 符号是否严格要求
'''
@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>')
'''
转换器
'default': # 不写类型就是default 示例:/<pk>
'string': UnicodeConverter,
'path': PathConverter,
'int': IntegerConverter,
了解
'any': AnyConverter,
'float': FloatConverter,
'uuid': UUIDConverter,