Flask框架
介绍
flask是基于python开发并且依赖于jinjia2模板和werkzeug wsgi服务的一个微型框架
werkzeug本质是socket服务端,用于接收http请求并对其进行预处理,然后触发flask框架,开发人员基于flask框架提供的功能对请求进行相应的处理,并返回给用户,如果返回给用户复杂的内容时,需要借助于jinja2模板来实现对模板的处理。即:将模板和数据进行渲染,将渲染的字符串返回给用户浏览器
Flask的两个主要核心应用是Werkzeug和模板引擎Jinja.
快速使用
# pip install flask 【目前最高版本2.2.2】
from flask import Flask
app = Flask(__name__) # 实例化得到对象
# 注册路由
@app.route('/')
def index():
return 'Hello World!'
if __name__ == '__main__':
app.run() # 括号内可以指定地址 不写就是默认地址加端口5000
登录展示用户信息案例
from flask import Flask, request, render_template, redirect, session, jsonifyf
from flask.views import MethodView
app = Flask(__name__)
# request虽然在全局导入的 但是在哪个视图函数用就是当次请求的request
# 使用session的话必须先设置key值
app.secret_key = 'shvhcdsmghtrdhknksbvasdavbjbhva'
# 用户字典
USERS = {
1: {'name': 'jason', 'age': 18, 'hobby': 'read'},
2: {'name': 'kevin', 'age': 19, 'hobby': 'run'},
3: {'name': 'tony', 'age': 20, 'hobby': 'dance'},
4: {'name': 'jerry', 'age': 21, 'hobby': 'sing'}, }
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'GET':
return render_template('login.html')
else:
username = request.form.get('username')
password = request.form.get('password')
if username == 'summer' and password == '123':
session['is_login'] = True # 写入cookie
return redirect('/index')
else:
return render_template('login.html', errors='用户名或密码错误')
@app.route('/index', methods=['GET'])
def index():
if session.get('is_login'):
return render_template('index.html', **{'users': USERS})
else:
return redirect('/login')
@app.route('/detail/<int:id>')
def detail(id):
if session.get('is_login'):
user = USERS.get(id)
return render_template('detail.html', **{'user': user})
else:
return redirect('/login')
if __name__ == '__main__':
app.run()
总结
1.注册路由:@app.route('/login',methodes=['GET','POST']) # methods允许请求的方式
2.新手四件套:
-返回模板信息:return render_template('index.html', **{'users': USERS})
# django里面的是context,flask可以直接使用**
-重定向:return redirect('/index')
-返回字符串:return '字符串'
-返回json格式:return jsonify
3.使用session 【全局使用,必须指定密钥】
app.secret_key = 'shvhcdsmghtrdhknksbvasdavbjbhva'
-设置值:session['key'] = value
eg: session['is_login'] = True # 写入cookie/session
-获取session:session.get('key')
4.转换器使用:
@app.route('/detail/<int:id>') # 直接在路由里配置 int后面的参数必须写在函数括号内
def detail(id):
pass
5.获取post请求的数据:
request.form
6.模板语法:使用的jinjia2【可以采用字典取值的方式,也可以直接点取值】
eg:{{v.name}} / {{v.get('name')}}/ {{v.['name']}}
配置文件
# flask的默认配置文件在app.config
【重要参数】
1:DEBUG:是否是调试模式
2:SECRET_KEY:项目密钥
3:SESSION_COOKIE_NAME:默认为session 可以自己指定
'''配置文件配置的多种方式''' 【最后都是写到了app.config中】
1. 直接使用app.debug = True
2. 通过app.config配置
app.config['DEBUG'] = True # config是个字典
3. 通过配置文件配置 【和django很像】
- 写一个settings.py,里面的配置名也是大写
DEBUG = True
- 将配置文件映射到config中,后期使用自己写的配置
app.config.from_pyfile('settings.py') 【括号内写配置文件的名称】
4. 通过类配置 【最常用的(上线和测试都可用)】
- 写一个setting.py ,将所有的配置以类的形式写在配置文件中
class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite://:memory:' # 自定义的配置
class ProductionConfig(Config):
DEBUG = False
DATABASE_URI = 'mysql://192.168.11.11/foo' # 上线数据库地址
class DevelopmentConfig(Config):
DEBUG = True
DATABASE_URI = 'mysql://127.0.0.1/foo' # 开发阶段本地数据库地址
- app.config.from_object('setting.DevelopmentConfig') # 测试阶段使用的配置类
- app.config.from_object('setting.ProductionConfig') # 上线使用的配置类
5.其他配置类型
- app.config.from_envvar('环境变量名称') # 写入到环境变量中
- app.config.from_json('json文件名称') # 配置直接写在json文件中
- app.config.from_mapping({'DEBUG':True}) # 配置直接从字典中映射过来
'''拓展芝士'''
# 分布式配置中心 【nocos,Apollo】
将分布式项目的配置单独写在一个分布式配置中心,以后如果需要修改配置文件信息直接在配置中心修改即可,不需要再去项目中一个个修改配置文件
获取分布式配置中心的配置: res = requests.get('配置中心的地址').json()
由于配置文件拉取下来在项目中是json格式,那么可以使用到下面的配置方式
app.config.from_mapping(res) # 将配置映射到项目中
路由系统
# 在flask中是以装饰器的形式写路由的
app.route('/login'<int:pk>,methods=['GET','POST']) 可以使用转换器/请求方式/路由别名
- 比较重要的几个转换器:string/path/int
- methods:规定的请求方式,只有写了才可以使用
- endpoint:路由的别名【如果路由重名的情况下,可以使用别名】
路由系统本质【部分源码分析】
# flask路由的本质是app对象的方法self.add_url_rule(rule,endpoint,f,**options)
@app.route('/login')
def login:
pass
装饰器的本质是:index=app.route('/login')(index)
def route(self, rule, **options):
# 1.login执行了@app.route('/login'),返回的是decorator,@app.route('/')(index)=@decorator(index)
def decorator(f):
# 此时的f就是index函数
endpoint = options.pop("endpoint", None)
# 2.self就是flask的对象app 执行了add_url_rule方法 返回了index
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
def add_url_rule(self,rule,endpoint,view_func,**options):
# 3.主要看add_url_rule方法的参数
pass
1.rule 路由 /login
2.endpoint 别名,没写就把函数名当作别名
3.view_func 视图函数不加括号 login
4.**options 可以将methods等参数打散传入
# 通过源码分析,路由地址可以写成以下方式
app.add_url_rule('/login',view_func=login)
add_url_rule的其他参数(使用频率不高)
1. defaults=None 当url中没有参数,函数需要传参数时,使用defaults={'k':'v'} 【类似于django路由中的kwargs】
eg: @app.route('/login',defaults={'name':'summer'})
def login(name):
pass
2. strict_slashes=None 对url后面的/是否必须要
eg: @app.route('/login',strict_slashes=False) # 如果是True的话就不能加/
访问路由:http://127.0.0.1:5000/index 和 http://127.0.0.1:5000/index/ 都可以
3. redirect_to=None 重定向到指定地址
eg: @app.route('/index/<int:nid>', redirect_to='/home/<nid>')
cbv的写法
from flask.views import MethodView
class Login(MethodView):
decorators = []
def get(self):
return ''
def post(self):
return ''
# 路由写法 【as_view必须传值,传的值是别名】
app.add_url_rule('/login',view_func=Login.as_view('userlogin'))
# cbv加装饰器的话 直接写一个参数即可 列表内可写多个
decorators = []
# 装饰器部分源码解读
def as_view(cls, name,*class_args, **class_kwargs)
if cls.decorators: # 如果decorators有值的话
for decorator in cls.decorators: # 循环执行列表里的装饰器
view = decorator(view) # 给视图类中的方法加装饰器
return view
cbv源码分析
# as_view()的执行流程
def as_view(cls, name,*class_args, **class_kwargs)
def view(**kwargs):
return self.dispatch_request(**kwargs)
return view
1.执行as_view(),返回了view,其实是执行了view(**kwargs),而view函数内又执行了self.dispatch_request
self就是当前视图类的对象 【也就是执行的的MethodView里的dispatch_request】
def dispatch_request(self, **kwargs):
meth = getattr(self, request.method.lower(), None)
if meth is None and request.method == "HEAD":
meth = getattr(self, "get", None)
return meth(**kwargs)
2.当请求来了,获取当前的类里面的小写方法get,此时的返回的meth是视图类中的get方法
endpoint相关源码分析
# 视图函数的路由装饰器参数endpoint
def add_url_rule(self,rule,endpoint:None,view_func:None,**options):
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint
'''
flask里的add_url_rule方法的参数endpoint默认为None,
当endpoint是None的时候,执行了_endpoint_from_view_func(view_func)把当前的视图函数当作参数
'''
def _endpoint_from_view_func(view_func):
assert view_func is not None,
return view_func.__name__
'''
assert断言该函数不为空
如果不为空的话返回了view_func.__name__
__name__就是当前函数的名字
也就是说 当endpoint为None的时候,会默认将函数名当作别名
'''
# view_func=Login.as_view(name='login') 括号里的就是别名,相当于endpoint
由于as_view()执行的是view的内存地址
endpoint又没有传值,那么就将函数的名字当作别名,但是as_view()返回的都是view,没法区分,就必须要写name
as_view()又必须传值,那么如果没有endpoint以name为值,如果传了endpoint就以endpoint的值为值
继承view写cbv
1.执行流程和MethodView是一样的
2.路由匹配成功执行self.dispatch_request
3.view里的self.dispatch_request是直接抛异常的
4.如果想要继承view写cbv的话,必须重写self.dispatch_request方法
【MethodView就是重写了self.dispatch_request】
模板语法
from flask import Flask, render_template,Markup
app = Flask(__name__)
@app.route('/')
def index():
# return render_template('test.html', name='lqz', age=19)
# return render_template('test.html',
# user={
# 1: {'name': 'lqz', 'age': 19, 'hobby': '篮球'},
# 2: {'name': 'lqz1', 'age': 20, 'hobby': '橄榄球'},
# 3: {'name': 'lqz2', 'age': 21, 'hobby': '乒乓球'},
# })
a='<a href="http://www.baidu.com">点我看美女</a>'
# a=Markup(a) 直接在后端就写好safe
return render_template('test.html',a=a)
if __name__ == '__main__':
app.run()
<body>
{#{{ name }}---{{ age }}#}
{#<table>#}
{# {% for k,v in user.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>#}
{#<table>#}
{# {% if name %}#}
{# <h1>Hello {{ name }}!</h1>#}
{# {% else %}#}
{# <h1>Hello World!</h1>#}
{# {% endif %}#}
{#</table>#}
{#{{ a|safe }}#}
{{ a}}
</body>
</html>
标签:endpoint,return,name,框架,Flask,app,login,view
From: https://www.cnblogs.com/Hsummer/p/16974390.html