Day 06
信号机制
我个人的理解,flask中的信号机制就类似于之前做安卓开发时用到的广播机制一样,在一个地方发送,在另一个地方监听,监听到了以后可以做出响应。Flask中的信号需要有一个命名空间,保证不同的信号之间不会混淆。
使用步骤:定义信号、监听信号、发送信号
# pip install blinker from blinker import Namespace ''' 用信号实现登录 ''' #定义信号 myspace = Namespace() login_signal = myspace.signal('login') #监听信号 def login_log(sender,username): now = datetime.now ip = request.remote_addr log_line = "{username}*{now}*{ip}".format(username=username, now=now,ip=ip) with open('login_log.txt','a') as f: f.write(log_line) login_signal.connect(login_log) #发送信号 login_signal.send(username='xxx')
欸,是不是非常简单又强大
flask内置的信号
-
template_rendered
def template_rendered_func(sender,template,context): ''' sender:不写默认为Null template:渲染的模板 context:发送给模板的上下文(g对象,request对象,session对象) ''' template_rendered.connect(template_rendered_func)
-
before_render_template
-
request_started
-
request_finished
-
request_tearing_down:request对象被销毁的时候
-
got_request_exception
def request_exception_log(sender,exception): ''' exception:异常信息 ''' got_request_exception.connect(request_exception_log)
-
appcontext_tearing_down
-
appcontext_pushed
-
appcontext_popped
-
message_flashed:调用了flask的'flashed'方法的信号(不常用)
Flask-Restful API
api规范
restful api:适用于在前端与后台进行通信的一套规范(前后端分离开发)。
协议:
采用http或https协议
数据传输格式:
都使用 json,而非 xml
url连接:
url连接中,不能有动词,只能有名词。并且对于一些名词,如果出现复数,应该在后面加 s。比如获取文章列表,应该使用 '/articles/',而不应该使用 '/get_article/'。
http请求的方法:
-
GET:从服务器获取资源
-
POST:在服务器上新建资源
-
PUT:在服务器上更新资源(客户端提供所有改变后的数据)
-
PATCH:在服务器上更新资源(客户端只提供需要改变的属性)
-
DELETE:从服务器上删除资源
状态码
状态码 | 原生描述 | 描述 |
---|---|---|
200 | OK | 成功响应 |
400 | INVALID REQUEST | 用户发出请求有错误 |
401 | Unauthorized | 用户没有权限访问这个请求 |
403 | Forbidden | 因为某些原因禁止访问 |
404 | NOT FOUND | 用户请求的 url 不存在 |
406 | NOT ACCEPTABLE | 用户请求不被接受(如参数传递错误) |
500 | Internal server error | 服务器内部错误,比如出现bug |
Flask-Restful使用
使用flask-restful定义视图函数的时候,要继承自flask_restful.Resource类,然后根据当前请求的 method 来定义相应的方法。基本使用示例:
from flask import Flask,render_template,url_for from flask_restful import Api,Resource app = Flask(__name__) # 用Api来绑定app api = Api(app) class LoginView(Resource): def post(self,username=None): return {'username':'xxx'} api.add_resource(LoginView,'/login/<username>/',endpoint='login') ''' 1.endpoint是用来给url_for反转url的时候指定的。如果不写,默认为视图名字的小写,这里是'loginview' 2.add_resource的第二个参数是访问这个视图的url,这个url跟之前的route一样,可以传递参数。不同的是,这个方法可以传递多个url来指定这个视图函数 如,api.add_resource(LoginView,'/login/<username>/','/register/'),这样的话这两个路由都会跳到这个视图处理 '''
参数验证
Flask-Restful 插件提供了类似 WTForms 来验证提交的数据是否合法的包,叫做 reqparse。基本使用:
parser = reqparse.RequestParser() parser.add_argument('username',type=str,help='请输入用户名', required=True) args = parser.parse_args()
函数的一些参数:
-
default:默认值
-
help:出错的提示信息
-
required:是否必须。默认为False
-
type:参数类型。如果指定,则会使用指定的类型进行强转
-
choices:一个列表,可选择其中的一个值
-
trim:是否去除前后空格
对于 type ,可以是python自带的一些数据类型,也可是使用 flask_restful.inputs 下的一些数据类型。比如:
-
url :判断是否是合法 url
-
regex:正则表达式 ( type=inputs.regex(r'...') )
-
date:将这个字符串转换为datetime.date数据类型
标准化参数返回
使用 fields 和 marshal_with
#导包 from flask_restful import fields, marshal_with class ArticleView(Resource): resource_field = { 'title': fields.String, 'content': fields.String } @marshal_with(resource_fields) def get(self): return {}
另一种操作:
#定义一个模型 class Article(): def __init__(self,title,content): self.title = title self.content = content article = Article(title='title',content='content') class ArticleView(Resource): resource_field = { 'title': fields.String, 'content': fields.String } @marshal_with(resource_fields) def get(self): return article ''' 重命名属性和默认值: attr_field = { 'attr1':field.String(attribute='attr2', defalult='xxx') } 加了attribute属性以后,返回的json数据中名字是attr1,但是实际去模型中匹配的字段名称是attr2 不指定default值时,若匹配不到则返回Null '''
想在返回的数据格式中形成比较复杂的结构,可以使用特殊字段实现。比如在字段中放置一个列表,可以使用 field.List;在字段中又是一个字典,可以使用 field.Nested。例:
resource_field = { 'username': field.String(), 'age': field.Integer, 'tags': field.List(field.String), 'more': field.Nested({ 'attr1': field.String #... }) 'more_and_more': field.List( field.Nested({ #... })) }
细节补充
-
flask-restful结合蓝图
可以把有关视图部分的类和函数等抽取成一个蓝图,实现功能模块化
# 新建 articleview.py from flask import Blueprint from flask_restful import Resource, fields, marshal_with, Api # 新建蓝图 article_bp = Blueprint('article', __name__,url_prefix='') # 把蓝图与接口绑定,注意:不再使用app绑定而是用新建的蓝图绑定 api = Api(article_bp) # 与视图有关的操作没有变化 class ArticleView(Resource): resource_field = { 'title': fields.String(default='ttl1') } @marshal_with(resource_field) def get(self): return {} api.add_resource(ArticleView, '/article/', endpoint='article')
在主app文件中注册蓝图,一个app可以有多个蓝图:
app.register_blueprint(article_bp)
-
flask-restful渲染模板
如果在接口中返回的是模板,即 return render_template('xxx.html') 的形式,调用接口后会把 html 中的内容当成一串 string 返回,而不会渲染成 html,要以 html 格式返回,需要在接口对应的蓝图中增加以下操作:
@api.representation('text/html') def output_html(data,code,headers): ''' data:传输数据 code:请求的状态码 headers:请求头 ''' resp = make_response(data) # 返回的必须是 Response 对象 return resp
flask有关的笔记暂时就到此为止了,有了基础知识的铺垫以后做些小型的开发应该还是没有问题的。