python3-开发进阶Flask的基础
一、概述
最大的特点:短小精悍、可拓展强的一个Web框架。注意点:上下文管理机制,依赖wsgi:werkzurg 模块
二、前奏学习werkzurg
先来回顾一个知识点:一个类加括号会执行__init__方法,一个对象加括号执行__call__方法
事例1:
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) #封装了请求和相应的对象
flask就是基于上面一步一步搭建起来的!
三、学习flask
第一个flask:
from flask import Flask duo=Flask(__name__) duo.run()
三行 启动了程序,但是访问url,发现是Not Found !!!
什么原因呢?按理说访问url,执行函数,返回结果,我们发现我们访问了,但是没有接收,在django应该怎么写,写个路由写个视图,在这也是一样
from flask import Flask duo=Flask(__name__) @duo.route('index') def index(): return "hello world" duo.run() #这下执行就访问成功
这个duo.run 就是启动socket,这个脚本要以主函数去运行的时候,采取执行duo.run,别人如果导入的时候,run是不应该执行的:
from flask import Flask duo=Flask(__name__) @duo.route('index') def index(): return "hello world" if __name__ == '__main__': duo.run()
一个flasl实现简单的登录:
from flask import Flask,render_template,request,redirect,session duo=Flask(__name__) duo.secret_key='shuai' #加密方式 @duo.route('/login',methods=['GET','POST']) #默认GET 别的请求还要添加 def login(): if request.method == 'GET': #return 'Login' #HttpResponse django 返回字符串 return render_template('login.html') #request.form ----------》#request.POST #request.args ----------》 #request.GET user=request.form.get('user') pwd=request.form.get('pwd') if user=='duoduo' and pwd =='123': session['user']=user return redirect('/index') return render_template('login.html',error='用户名或密码错误') @duo.route('/index') def index(): user=session.get('user') if not user: return redirect('login') return render_template('index.html') if __name__ == '__main__': duo.run()
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>用户登入</h1> <form method="post"> <input type="text" name="user"> <input type="password" name="pwd"> <input type="submit" value="提交">{{error}} </form> </body> </html>
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="x-ua-compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Title</title> </head> <body> <h1>欢迎使用</h1> <img src="/static/111.jpg" alt=""> #图片自己找个 </body> </html>
三、Flask
1、简介
1、配置文件
模块+静态文件 Flask(__name__,...)
2、路由系统 装饰器实现的
@duo.route('/index',methods=['GET'])
3、视图 也有fbv,cbv
4、请求相关 导入就能用,django 而是参数
request.form
request.args
request.method
5、响应
字符串‘’
render
redirect
6、模块渲染
7、session
session['xxx']=123
session.get('xxx')
8、fiash (闪现)
9、中间件 基本不用 请求前的操作
10、特殊的装饰器
假使一个setting.py:
class Foo: DEBUG=True TEST=True
一个脚本duoduo.py
path='setting.Foo'
我们如何在path中将Foo这个类找到?如何获取其中大写的静态字段的值:
import importlib path='setting.Foo' p,c=path.rsplit('.',maxsplit=1) m=importlib.import_module(p) cls=getattr(m,c) for key in dir(cls): if key.isupper(): print(key,getattr(cls,key)) #其实这就是配置文件导入原理
2、详解
1、配置文件
flask的配置文件在哪里呢?这些都是默认的配置文件,
from flask import Flask duo=Flask(__name__) print(duo.config) #<Config {'ENV': 'production', 'DEBUG': False, 'TESTING': False, 'PROPAGATE_EXCEPTIONS': None,
'PRESERVE_CONTEXT_ON_EXCEPTION': None, 'SECRET_KEY': None, 'PERMANENT_SESSION_LIFETIME': datetime.timedelta(31),
'USE_X_SENDFILE': False, 'SERVER_NAME': None, 'APPLICATION_ROOT': '/', 'SESSION_COOKIE_NAME': 'session',
'SESSION_COOKIE_DOMAIN': None, 'SESSION_COOKIE_PATH': None, 'SESSION_COOKIE_HTTPONLY': True,
'SESSION_COOKIE_SECURE': False, 'SESSION_COOKIE_SAMESITE': None, 'SESSION_REFRESH_EACH_REQUEST': True,
'MAX_CONTENT_LENGTH': None, 'SEND_FILE_MAX_AGE_DEFAULT': datetime.timedelta(0, 43200), 'TRAP_BAD_REQUEST_ERRORS': None,
'TRAP_HTTP_EXCEPTIONS': False, 'EXPLAIN_TEMPLATE_LOADING': False, 'PREFERRED_URL_SCHEME': 'http', 'JSON_AS_ASCII': True,
'JSON_SORT_KEYS': True, 'JSONIFY_PRETTYPRINT_REGULAR': False, 'JSONIFY_MIMETYPE': 'application/json',
'TEMPLATES_AUTO_RELOAD': None, 'MAX_COOKIE_SIZE': 4093}>
配置文件是可以修改的,那在哪里改?我们这有这样一个语法:
duo.config.from_object('setting.Foo') #还是上面的setting.py文件
我们来看看.from_object 中的源码:
我们以后的配置文件,可以生成不一样的类,开发环境一个类,线上环境一个类,相同的静态属性一个类,我们根据现实的环境只需改一个类名字就可以了
2、路由系统
@duo.route(url,methods(允许请求的方式),endpoint(值))
-endpoint ,反向生成URL,如果没有endpoint设定的值,那么默认的这就是函数名
-url_for('endpoint设定的值')
from flask import Flask,url_for duo=Flask(__name__) # print(duo.config) duo.config.from_object('setting.Foo') # print(duo.config) @duo.route('/index/',methods=['GET','POST']) #endpoint就是django反向生成的name,如果不写endpoint,url_for后面的值就是函数名 def index(): print(url_for('index')) #反向生成url return "hello world" if __name__ == '__main__': duo.run()
我们在django中有的时候url会带上对象的nid值,这个在flask中是什么的格式呢?
- @duo.route('/user/<username>') 字符串
- @duo.route('/post/<int:post_id>') 整数
- @duo.route('/post/<float:post_id>') 浮点
- @duo.route('/post/<path:path>') 路径
- @duo.route('/login', methods=['GET', 'POST'])
但是默认是不支持正则!
这就是动态的路由
from flask import Flask,url_for duo=Flask(__name__) # print(duo.config) duo.config.from_object('setting.Foo') # print(duo.config) @duo.route('/index/<int:nid>',methods=['GET','POST']) #int是用来约束在url的值 def index(nid): print(nid) print(url_for('index',nid=1)) #有参数要加参数 return "hello world" if __name__ == '__main__': duo.run()
3、FBV(CBV后面再介绍)
4、请求相关,响应相关
from flask import Flask,jsonify,make_response duo=Flask(__name__) @duo.route('/index/<int:nid>',methods=['GET','POST']) #int是用来约束在url的值 def index(nid): # 请求相关信息 # request.method # request.args # request.form # request.values # request.cookies # request.headers # request.path # request.full_path # request.script_root # request.url # request.base_url # request.url_root # request.host_url # request.host # request.files # obj = request.files['the_file_name'] # obj.save('/var/www/uploads/' + secure_filename(f.filename))
# 响应相关信息 # return "字符串" # return render_template('html模板路径',**{}) # return redirect('/index.html') # return jsonify({'k1':'v1'}) #jsonify帮你序列化 obj=make_response('Index') #把返回给用户的字符串,封装到这个对象 obj.headers['duoduo']=666 #设置响应头 return obj if __name__ == '__main__': duo.run()
运行后:
6、模板的渲染
一个登入验证,可以导入before_request,没有返回值就是可以通过,有返回值就无法通过
from flask import Flask,request,before_request,session duo=Flask(__name__) @duo.before_request def xxxxx(): if request.path =='/login': #只有登入视图可以访问 return None if session.get('user') : return None return redirect('login') # 上面不通过,返回登入页面
-基本数据类型:可以执行python的语法,如:dict.get() list['xx']
-传入函数
django,自动执行
flask,不自动执行
-全局定义函数
@duo.template_global()
@duo.template_filter()
-模板的继承
{%extends '给谁'%}
{%block content%}
{% endblock%}
-include 直接加页面
-安全方式展示
前端:{{obj|safe}}
后端:Markup('obj')
7、session
session在视图中可以字典来使用,为什么能当作字典,我们来看一下源码:
from flask.sessions import SecureCookieSession
继承了dict,不用多说什么
当请求刚进来时:flask读取cookie中session对应的值:将这个值解密并反序列化成字典,放入内存,以便视图函数使用,
当请求结束时:flask会读取内存中字典的值,在进行序列化+加密,写入到用户的cookie中。(这就是session的机制)
session的配置是可以改的,关于session有以下几点:
'PERMANENT_SESSION_LIFETIME': timedelta(days=31), #生命周期 'SESSION_COOKIE_NAME': 'session' #名称 'SESSION_COOKIE_DOMAIN': None #域名 'SESSION_COOKIE_PATH': None #路径 ‘SESSION_COOKIE_HTTPONLY': True #支持HP读取 'SESSION_COOKIE_SECURE': False #安全性 'SESSION_REFRESH_EACH_REQUEST': True #最后一次访问的时间保持
8、flash
在session中存储一会数据,读取时通过pop将数据移除,以此来创造一个效果,只存一次,只能取一次
实例:
from flask import Flask,flash,get_flashed_messages duo=Flask(__name__) duo.secret_key='duoduo' #这是一个容易忘记的点 #出现secret_key 的报错就是这个设置 @duo.route('/page1') def page1(): flash('大娃','boy') flash('二娃','boy') flash('蛇精','girl') return 'session' @duo.route('/page2') def page2(): print(get_flashed_messages(category_filter=['boy'])) return 'session' if __name__ == '__main__': duo.run()
访问一下,取一下,我们来看看源码:
9、中间件
那我们先来了解一下flask是怎么运行起来的:
先写一个简单的脚本:
from flask import Flask duo=Flask(__name__) @duo.route('/index') def index(): print('index') return 'Index' if __name__ == '__main__': duo.run()
首先,先点开源码的duo.run:
run的self就是flask的对象,请求进来第三给参数后面加括号,是不是flask的对象加括号,就是调用,对象调用执行__call__方法:
duo.__call__ #进去看看
当上面的脚本运行,只有请求访问,才执行__call__方法
一个简单的应用
from flask import Flask duo=Flask(__name__) @duo.route('/index') def index(): print('index') return 'Index' class Middleware(object): def __init__(self,old): self.old=old def __call__(self, *args, **kwargs): print('执行前') ret=self.old(*args,**kwargs) print('执行后') return ret if __name__ == '__main__': duo.wsgi_app=Middleware(duo.wsgi_app) duo.run()
10、特殊的装饰器(重点)
before_request #谁先定义执行
after_request #从后往上执行
这上面两个原理就是把函数名放到一个列表,然后循环的机制
from flask import Flask duo=Flask(__name__) @duo.before_request def x1(): print('before') @duo.after_request def x2(reponse): #这里必须要有返回值 print('after') return reponse @duo.route('/index1') def index1(): print('index') return 'Index' @duo.route('/order') def order(): print('order') return 'order' if __name__ == '__main__': duo.run()
这里有一个注意点就是,before_request有返回值的话,要走所有的after_request ,在django1.9以前都只是这个流程,后来改了机制,
我们发现1.10以后,走最外面一个中间件就返回。
before_first_request #只执行启动起来 首次,后就不再执行,后面详细看源码
template_global # 渲染 全局定义函数
template_filter # 不一样的全局定义函数
errorhandler #定制错误信息
@duo.errorhandler(404) def not_found(arg): print(arg) return '没找到' #定制错误信息的页面比较常用