Flask 1 框架基础
Flask 基础
5步快速搭建一个项目
flask是一个轻量级的web框架,只是用一个脚本就能搭建起一个项目
#1,导入模块
from flask import Flask,request
#2,实例化Flask类得到一个app对象
app=Flask(__name__)
#3,配置路由
@app.route('/')
#4,处理请求的函数
def index():
# 当前请求地址,当前请求携带过来的数据
return 'hello world'
#5,启动项目
if __name__ == '__main__':
app.run()
# 请求来了,会执行 app(request),触发__call__方法
1, 路由写法(路径,支持的请求方式,别名)
@app.route('/login',methods=['GET','POST'],endpoint='l1')
2 返回格式:
return '字符串' #直接返回字符串
return render_template('index.html') #返回一个页面
return redirect('/login') #重定向
3模板语言渲染
-使用jinja2,和Django的dtl类似,但是比dtl强大
一 项目配置
方法1:直接在程序内修改
app.config['DEBUG'] = True
PS: 由于Config对象本质上是字典,所以还可以使用 app.config.update(...)
方法2:使用配置文件(这个方法和Django相似)
#新建py文件,内容为配置信息
settings.py
DEBUG = True
#引入配置文件
app.config.from_pyfile("python文件名称")
方法3:使用配置类
#新建py文件,内容为配置类
app.config.from_object('settings.TestingConfig')
class Config(object):
DEBUG = False
TESTING = False
DATABASE_URI = 'sqlite://:memory:'
class ProductionConfig(Config):
DATABASE_URI = 'mysql://user@localhost/foo'
class DevelopmentConfig(Config):
DEBUG = True
class TestingConfig(Config):
TESTING = True
二 路由系统
#flask用装饰器的方式配置路由,一般传入3个参数,依次为路径,允许的方法,别名
@app.route('/detail/<int:nid>',methods=['GET'],endpoint='detail')
路由参数-路径
有名分组:
和Django类似,<student_id>匹配的值会以student_id为key的形式接受
@app.route('/student_list/<student_id>/')
def student_list(student_id):
return '学生{}号的信息'.format(student_id)
路由参数-请求方法
methods=['GET'],允许什么方法就在列表里添加什么方法
路由参数-别名
endpint
参数是写在注册路由的装饰器中的一个参数,学名叫端点,我们可以理解为函数的别名。如果不指定endpoint,默认就以函数名作为端点名。
Copy@app.route('/fbvtest/',methods=['GET','POST'],endpoint='fbv')
def fbvtest():
url_demo = url_for('fbv')
return '利用视图函数别名翻转的url为:{}'.format(url_demo)
关键词:
- 利用
@app.route()
的endpoint='fbv'
参数可以自由指定端点名,url_for可以根据指定的端点名进行翻转。
注册路由参数详解
常用的参数
@app.route和app.add_url_rule参数:
rule, URL规则
view_func, 视图函数名称
endpoint = None, 名称,用于反向生成URL,即: url_for('名称')
methods = None, 允许的请求方式,如:["GET", "POST"]
不常用的参数
(1) 对URL最后的 / 符号是否严格要求 strict_slashes = False
strict_slashes = False
'''
@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
'''
(2) 重定向到指定地址redirect_to=“ ”
@app.route("/",redirect_to='/home/')
def index():
return '根路径'
@app.route("/home/")
def admin_demo():
return 'home路径'
(3) 为函数提供默认参数值
defaults = None, 默认值, 当URL中无参数,函数需要参数时,使用defaults = {'k': 'v'}
(4)子域名设置subdomain=“ ”
from flask import Flask,url_for
app = Flask(__name__)
app.debug = True
'''
先在hosts设置域名解析(就是在本机的hosts文件上编辑上域名对应ip的关系)
域名解析会先解析本地如果没有再解析dns服务器
C:\Windows\System32\drivers\etc\hosts
127.0.0.1 mark.com
127.0.0.1 admin.mark.com
'''
app.config['SERVER_NAME'] = 'mark.com:5000' # 这个代表访问这个域名的时候要访问5000端口
@app.route("/")
def index():
return '设置域名成功'
@app.route("/admin_demo/",subdomain='admin')
def admin_demo():
return '设置子域名成功'
'''
在浏览器中访问主域名
mark.com:5000/
在浏览器中访问子域名
admin.mark.com:5000/admin_demo/
注意:后面跟的path路径部分正常写
'''
if __name__ == '__main__':
app.run(host='127.0.0.1',port=5000) # 测试服务器不稳定,尽量手动制定ip和端口
装饰器注册路由源码浅析
(1) 首先写一个小视图函数
Copy#注册装饰器的原理
#1 v = app.route('/source_code_demo/',endpoint='source_code')
#2 v(source_code_demo)
@app.route('/source_code_demo/',endpoint='source_code')
def source_code_demo():
return 'source_code_demo'
(2) 查看app.route()
源码
def route(self, rule, **options):
def decorator(f):
endpoint = options.pop('endpoint', None)
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
解析:
- ,发现
route()
返回的是decorator
函数地址,然后基于语法糖和装饰器的原理,decorator会加括号运行,像这样decorator(source_code_demo)
decorator
函数中首先取出endpoint
,然后运行self.add_url_rule(rule, endpoint, f, **options)
- 所以
self.add_url_rule(rule, endpoint, f, **options)
就是注册路由的核心
(3) 点进self.add_url_rule(rule, endpoint, f, **options)
查看源码,
再点进_endpoint_from_view_func(view_func)
查看源码
@setupmethod
def add_url_rule(self, rule, endpoint=None, view_func=None,
provide_automatic_options=None, **options):
if endpoint is None:
endpoint = _endpoint_from_view_func(view_func)
options['endpoint'] = endpoint
methods = options.pop('methods', None)
if methods is None:
methods = getattr(view_func, 'methods', None) or ('GET',)
def _endpoint_from_view_func(view_func):
assert view_func is not None, 'expected view func if endpoint ' \
'is not provided.'
return view_func.__name__
解析:
- 由上述代码我们可以直到如果没有指定
endpoint
,我们调用了_endpoint_from_view_func()
- 观察
_endpoint_from_view_func
函数我们可以知道,返回了视图函数的名字给了endpoint
赋值 methos
没有指定会给methos赋默认值('GET',)
小结:
self.add_url_rule(rule, endpoint, f, options)
就是注册路由的核心- 观察
_endpoint_from_view_func
函数我们可以知道,返回了视图函数的名字给了endpoint
赋值 methos
没有指定会给methods
赋默认值('GET',)
另一种注册路由的方式---app.add_url_rule()
通过看上一个小节写的源码,现在我们知道了app.route() 的核心就是self.add_url_rule(rule, endpoint, f, options)
就是注册路由的核心。所以我们可以直接使用app.add_url_rule()
的方式来注册路由。
实例:
def add_url_test():
return '实现了add_url方式注册路由'
# url 端点 函数地址
app.add_url_rule('/add_url_test/',endpoint='add_demo',view_func=add_url_test)
转换器
可以对<student_id>要匹配的值进行限定,如:限定student_id必须为整数类型
@app.route('/student_list/<int:student_id>/')
def article_detail(student_id):
return '学生{}号的信息'.format(student_id)
主要有这几种类型过滤:
string
: 默认的数据类型,接收没有任何斜杠"\ /"的字符串
int
: 整型
float
: 浮点型
path
: 和string类型相似,但是接受斜杠,如:可以接受参数/aa/bb/cc/多条放在一起
uuid
: 只接受uuid格式的字符串字符串
any
: 可以指定多种路径,如下面的例子
@app.route('/<any(student,class):url_path>/<id>/')
def item(url_path, id):
if url_path == 'student':
return '学生{}详情'.format(id)
else:
return '班级{}详情'.format(id)
处理动态路由
自定义一个类,该通过继承werkzeug.routing 的BaseConverter
类不光可以实现正则匹配,我们介绍一下以下两个方法:
-
在该类中实现 to_python 方法:
这个方法的返回值,将会传递给视图函数的形参。我们可以利用这个方法实现处理url中动态路由部分。
-
在该类中实现 to_url 方法:
翻转url的时候也就是使用url_for函数的时候,我们传入指定的动态路由部分,触发to_url方法,这个方法的返回值,会拼接在非动态路由上,从而实现生成符合要求的url格式。
Copyfrom flask import Flask,request,url_for
from werkzeug.routing import BaseConverter
app = Flask(__name__)
app.debug =True
class ListConverter(BaseConverter):
regex = '.*' # 这个regex代表都匹配的意思,可以根据自己的需求制定url规则
def to_python(self, value):
'''这个函数用于拿到了路由里的动态参数赋值给value,
可以在to_python进行操作动态参数,
返回操作完的的结果给视图函数的形参'''
return value.split('+')
def to_url(self, value):
'''这个函数用于和url_for连用,
url_for通过指定给动态参数(以关键字实参的形式)赋值给value
我们可以根据我们的需求操作url_for传进来的参数,
然后返回一个理想的动态路由内容拼接在url上'''
return '+'.join(value)
app.url_map.converters['list'] = ListConverter
@app.route('/student_list/<list:students>/')
def student_list(students):
print(url_for('student_list',students=['a','b'])) # 输出 /student_list/a+b/
return '{}'.format(students)
if __name__ == '__main__':
app.run()