- 01 今日内容概要
- 02 内容回顾
- 03 Flask框架:配置文件导入原理
- 04 Flask框架:配置文件使用
- 05 Flask框架:路由系统
- 06 Flask框架:请求和响应相关
- 07 示例:学生管理(一)
- 08 示例:学生管理(二)
- 09 Flask框架:模板
- 10 Flask框架:Session
- 11 Flask框架:Flash和特殊装饰器
- 12 Flask框架:中间件
- 13 Flask框架:特殊装饰器
- 14 今日内容总结
01 今日内容概要
1.1 Web框架的基础组成——urls、views;
1.2 路由->视图;
1.3 配置文件的处理;
1.4 路由系统(与Django有些不同,通过装饰器做的)
1.5 视图函数;
1.6 请求相关的数据不一样;
1.7 响应相关的数据不一样;
1.8 模板的渲染;
1.9 不是所有的Web框架都提供session,Flask提供;
1.10 闪现——取一下就没有了;
1.11 中间件;
1.12 蓝图——blueprint,对Flask程序进行目录结构的划分;
1.13 特殊的装饰器;
02 内容回顾
2.1 谈谈Django和Flask的对比、认知;
2.1.1 Django大而全,内部提供了很多的组件,比如ORM、admin、form以及ModelForm、分页等缓存、信号;Flask短小精悍,轻量级,可拓展性很高,适用于小型网站;
2.1.2 Flask可拓展性更高,自定义程度高;
2.1.3 Flask第三方组件拓展,会变得同Django一样;
2.1.4 Django和Flask哪个好呢?就我个人而言,如果比较熟悉的话,Flask更加适合!
2.2 Flask的Django的最大不同点?
2.2.1 request、session
2.3 Flask的知识点
2.3.1 模板和静态文件,在实例化时候配置,app = Flask(__name__,...)
2.3.2 路由——@app.route('/index',methods = ["GET"])
2.3.3 请求:request.form\request.args\request.method
2.3.4 响应:render、redirect
2.2.5 session引入方式:session['score'] = 123,获取方式推荐:session.get('score')不会报错!
2.4 路飞学城总共有几个项目?
2.4.1 管理后台
2.4.2 导师后台
2.4.3 主站(www.luffycity.com)——Vue:2.0;Django:1.11.1
2.5 路飞学城的主站业务?
2.5.1 课程
- 课程列表
- 课程详细
- 课程大纲、导师、推荐课程
- 价格策略
- 章节和课时
- 常见问题
2.5.2 深科技
- 文章列表
- 文章详细
- 收藏
- 评论
- 点赞
2.5.3 支付
- 购物车
- 结算中心
- 立即支付
- Redis(是否做持久化,AOM&RDB)
- 支付宝
- 消息推送——微信服务号
- 构建数据结构——redis中的key进行拼接;
- 购物车超时限制
- 优惠券+贝里+支付宝
2.5.4 个人中心
2.5.5 学习中心
2.5.6 播放视频——CC视频,是否加密?给CC视频打个广告:https://www.bokecc.com/
- 如果购买
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=7,0,0,0" width="600" height="490" id="cc_A421CCBE1873EA0C9C33DC5901307461"><param name="movie" value="https://p.bokecc.com/flash/single/2660F3A686840FA2_A421CCBE1873EA0C9C33DC5901307461_false_654628F0907DA9AD_1/player.swf" /><param name="allowFullScreen" value="true" /><param name="allowScriptAccess" value="always" /><param value="transparent" name="wmode" /><embed src="https://p.bokecc.com/flash/single/2660F3A686840FA2_A421CCBE1873EA0C9C33DC5901307461_false_654628F0907DA9AD_1/player.swf" width="600" height="490" name="cc_A421CCBE1873EA0C9C33DC5901307461" allowFullScreen="true" wmode="transparent" allowScriptAccess="always" pluginspage="http://www.macromedia.com/go/getflashplayer" type="application/x-shockwave-flash"/></object>
03 Flask框架:配置文件导入原理
3.1 找到类的方式方法(通过一个路径“settings.Foo”可以找到类并获取其中的大写的静态字段);
settings.py;
class Foo: DEBUG = True TEST = True
xx.py;
import importlib path = "settings.Foo" p, c = path.rsplit('.', maxsplit=1) m = importlib.import_module(p) cls = getattr(m, c) print(cls) # <class 'settings.Foo'> # 如何找到这个类呢? for key in dir(cls): if key.isupper(): print(key, getattr(cls, key))
04 Flask框架:配置文件使用
4.1 Flask配置文件之app.config;
from flask import Flask, render_template, redirect, request, session app = Flask(__name__) print(app.config) # app.config.from_object("settings.Dev") # 推荐使用该方式; app.config.from_object("settings.Production") # 推荐使用该方式; print(app.confg) ''' <Config { 'ENV': 'development', '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}> ''' if __name__ == '__main__': app.run()
4.2 配置文件的灵活使用方式;
4.2.1 通过引用settings配置文件中的内容进行赋值修改app.config.from_object("settings.Production")# 推荐使用该方式;
4.2.2 在settings配置文件中,通过定义父类,子类继承父类的方法,进行“开发、测试、预上线、生产环境等”灵活配置;
class Config(object): DEBUG = False TESTING = False DATABASE_URL = 'jdbc:sqlite:identifier.sqlite' class Development(Config): """开发环境配置""" DATABASE_URL = 'mysql://username@localhost/foo' class Testing(Config): """测试环境配置""" DATABASE_URL = 'mysql://username@test.cuixiaozhao.com/foo' class preannouncement(Config): """预上线环境配置""" DATABASE_URL = 'mysql://username@147.198.189.125/foo' class Production(Config): """生产环境配置""" DATABASE_URL = 'mysql://username@47.98.89.123/foo'
05 Flask框架:路由系统
5.1 endpoint,反向生成URL,如果不指定,默认为函数名;
5.2 url_for('endpoint');
5.3 设置动态路由;
from flask import Flask, render_template, redirect, request, session, url_for app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; print(app.config) # @app.route('/index/<int:nid>', methods=['GET', 'POST'], endpoint='n1') # 作用类似于Diango中的name属性,默认值为函数名; @app.route('/index/<int:nid>', methods=['GET', 'POST']) # 反向生成,作用类似于Diango中的name属性,默认值为函数名; def index(nid): print(nid) print(url_for('n1', nid=91)) # 如果没有指定endpoint参数,自行指定! return 'Index' if __name__ == '__main__': app.run()
5.4 常用的路由系统;
@app.route('/user/<username>') @app.route('/post/<int:post_id>') @app.route('/post/<float:post_id>') @app.route('/post/<path:path>') @app.route('/login', methods=['GET', 'POST']) 常用路由系统有以上五种,所有的路由系统都是基于一下对应关系来处理: DEFAULT_CONVERTERS = { 'default': UnicodeConverter, 'string': UnicodeConverter, 'any': AnyConverter, 'path': PathConverter, 'int': IntegerConverter, 'float': FloatConverter, 'uuid': UUIDConverter, }
06 Flask框架:请求和响应相关
6.1 请求相关的数据;
6.2 响应相关的数据;
from flask import Flask, render_template, redirect, request, session, url_for, make_response app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; print(app.config) # @app.route('/index/<int:nid>', methods=['GET', 'POST'], endpoint='n1') # 作用类似于Diango中的name属性,默认值为函数名; @app.route('/index/<int:nid>', methods=['GET', 'POST']) # 反向生成,作用类似于Diango中的name属性,默认值为函数名; def index(nid): print(nid) print(url_for('n1', nid=91)) # 如果没有指定endpoint参数,自行指定! # #########################请求相关################################### # 请求相关信息 # 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'}) # 设置响应头,引入make_response; # response = make_response(render_template('index.html')) # response是flask.wrappers.Response类型 # response.delete_cookie('key') # response.set_cookie('key', 'value') # response.headers['X-Something'] = 'A value' # return response return 'Index' if __name__ == '__main__': app.run()
07 示例:学生管理(一)
7.1 编写路由以及视图函数;
from flask import Flask, render_template, redirect, request, session, url_for, make_response app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; STUDENT_DICT = { 1: {'name': '崔晓昭', 'age': 18, 'gender': '男'}, 2: {'name': '崔晓姗', 'age': 20, 'gender': '女'}, 3: {'name': '崔晓丝', 'age': 22, 'gender': '女'}, } @app.route('/index/') def index(): return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info) if __name__ == '__main__': app.run()
7.2 模本配置,多数语法与Python十分相似;
index.html;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>学生列表</h1> <table border="1px"> <thead> <tr> <th>ID</th> <th>姓名</th> <th>年龄</th> <th>性别</th> <th>选项</th> </tr> </thead> <tbody> {% for k,v in stu_dic.items() %} <tr> <td>{{ k }}</td> <td>{{ v.name }}</td> <td>{{ v.age }}</td> <td>{{ v.gender }}</td> <td> <a href="/detail/{{ k }}">查看详细</a> | <a href="/delete/{{ k }}">删除</a> </td> </tr> {% endfor %} </tbody> </table> </body> </html>
detail.html;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h1>学生详细</h1> <ul> {% for item in info.values() %} <li>{{ item }}</li> {% endfor %} </ul> </body> </html>
08 示例:学生管理(二)
8.1 史上最LOW的实现方式,Copy、Paste不符合高端程序员的秉性;
from flask import Flask, render_template, redirect, request, session, url_for, make_response app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; STUDENT_DICT = { 1: {'name': '崔晓昭', 'age': 18, 'gender': '男'}, 2: {'name': '崔晓姗', 'age': 20, 'gender': '女'}, 3: {'name': '崔晓丝', 'age': 22, 'gen der': '女'}, } @app.route('/login/', methods=["GET", "POST"]) def login(): if request.method == "GET": return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'oldboy' and pwd == '666': session['user'] = user return redirect('/index') return render_template('login.html', error='用户名或者密码错误!') @app.route('/index/') def index(): if not session.get('user'): return redirect(url_for('login')) return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') def delete(nid): if not session.get('user'): return redirect(url_for('login')) del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') def detail(nid): if not session.get('user'): return redirect(url_for('login')) info = STUDENT_DICT[nid] return render_template('detail.html', info=info) if __name__ == '__main__': app.run()
8.2 添加装饰器的方法,适用于小范围添加功能;
from flask import Flask, render_template, redirect, request, session, url_for, make_response app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; STUDENT_DICT = { 1: {'name': '崔晓昭', 'age': 18, 'gender': '男'}, 2: {'name': '崔晓姗', 'age': 20, 'gender': '女'}, 3: {'name': '崔晓丝', 'age': 22, 'gen der': '女'}, } import functools def auth(func): @functools.wraps(func) def inner(*args, **kwargs): if not session.get('user'): return redirect(url_for('login')) ret = func(*args, **kwargs) return ret return inner @app.route('/login/', methods=["GET", "POST"]) def login(): if request.method == "GET": return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'oldboy' and pwd == '666': session['user'] = user return redirect('/index') return render_template('login.html', error='用户名或者密码错误!') @app.route('/index/') @auth def index(): return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') @auth def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') @auth def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info) if __name__ == '__main__': app.run()
8.3 适用于批量添加功能,类似于“中间件”的原理;
from flask import Flask, render_template, redirect, request, session, url_for, make_response app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; STUDENT_DICT = { 1: {'name': '崔晓昭', 'age': 18, 'gender': '男'}, 2: {'name': '崔晓姗', 'age': 20, 'gender': '女'}, 3: {'name': '崔晓丝', 'age': 22, 'gen der': '女'}, } @app.before_request def XXXX(): if request.path == '/login': return None if session.get('user'): return None return redirect('/login') @app.route('/login/', methods=["GET", "POST"]) def login(): if request.method == "GET": return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'oldboy' and pwd == '666': session['user'] = user return redirect('/index') return render_template('login.html', error='用户名或者密码错误!') @app.route('/index/') def index(): return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info) if __name__ == '__main__': app.run()
09 Flask框架:模板
9.1 模板渲染;
9.1.1 基本数据类型——可以执行Python的基础语法,如:dict.get(),list['xx'];
tpl.html;
{% extends 'layout.html' %} {% block content %} {{ users.0 }} {{ users[0] }} {{ txt|safe }} {{ func }} {{ func(6) }} {{ sb(1,100) }} {{ 1|db(1800,92) }} {% if 1|db(2,3) %} <div>666</div> {% else %} <div>999</div> {% endif %} {% include 'form.html' %} {% macro ccc(name,type = 'text',value = '') %} <h1>宏</h1> <input type="{{ type }}" name="{{ name }}" value="{{ value }}"> <input type="submit" value="提交"> {% endmacro %} {{ ccc('n1') }} {{ ccc('n2') }} {% endblock %}
9.1.2 传入函数func;
9.1.3 全局定义函数——@app.template_global()、@app.template_filter();
9.1.4 模板继承extends结合block方法;
layout.html;
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>layout</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> {% block content %} {% endblock %} </body> </html>
9.1.5 include方法引入模板文件{% include 'form.html' %};
form.html;
<form action=""> cuixiaozhao cuixiaoshan cuixiaosi cuixiaolei </form>
9.1.6 定义宏;
9.1.7 安全;
- 前端'txt'|safe参数;
- 后端Markup('fdskhfdjksa');
app.py;
from flask import Flask, render_template, redirect, request, session, url_for, make_response, Markup app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; STUDENT_DICT = { 1: {'name': '崔晓昭', 'age': 18, 'gender': '男'}, 2: {'name': '崔晓姗', 'age': 20, 'gender': '女'}, 3: {'name': '崔晓丝', 'age': 22, 'gen der': '女'}, } # @app.before_request # def XXXX(): # if request.path == '/login': # return None # if session.get('user'): # return None # return redirect('/login') @app.route('/login/', methods=["GET", "POST"]) def login(): if request.method == "GET": return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'oldboy' and pwd == '666': session['user'] = user return redirect('/index') return render_template('login.html', error='用户名或者密码错误!') @app.route('/index/') def index(): return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info) @app.route('/tpl/') def tpl(): context = { 'users': ['longtai', 'liusong', 'zhaohuhu'], 'txt': Markup("<input type='text'/>"), 'func': func, } return render_template('tpl.html', **context) def func(arg): return arg + 1 @app.template_global() def sb(a1, a2): return a1 + a2 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 # {{ 1|db(1800,92) }} if __name__ == '__main__': app.run()
10 Flask框架:Session
10.1 session的生成;
10.2 Flask中的session原理——读取cookie中session对应的值;eyJrMiI6NDU2fQ.DnFwbQ.TF4LMMk1g1WEk1NfQnmCS1OSN6w ,将改值解密并反序列化成字典;当请求结束时候,Flask会读取内存中的字典的值,进行序列化+加密,写入到用户cookies中。
11 Flask框架:Flash和特殊装饰器
11.1 闪现的概念——Flash;
from flask import Flask, render_template, redirect, request, session, url_for, make_response, Markup, flash, \ get_flashed_messages app = Flask(__name__) app.config.from_object("settings.Production") # 推荐使用该方式; STUDENT_DICT = { 1: {'name': '崔晓昭', 'age': 18, 'gender': '男'}, 2: {'name': '崔晓姗', 'age': 20, 'gender': '女'}, 3: {'name': '崔晓丝', 'age': 22, 'gen der': '女'}, } # @app.before_request # def XXXX(): # if request.path == '/login': # return None # if session.get('user'): # return None # return redirect('/login') @app.route('/login/', methods=["GET", "POST"]) def login(): if request.method == "GET": return render_template('login.html') user = request.form.get('user') pwd = request.form.get('pwd') if user == 'oldboy' and pwd == '666': session['user'] = user return redirect('/index') return render_template('login.html', error='用户名或者密码错误!') @app.route('/index/') def index(): return render_template('index.html', stu_dic=STUDENT_DICT) @app.route('/delete/<int:nid>') def delete(nid): del STUDENT_DICT[nid] return redirect(url_for('index')) @app.route('/detail/<int:nid>') def detail(nid): info = STUDENT_DICT[nid] return render_template('detail.html', info=info) @app.route('/tpl/') def tpl(): context = { 'users': ['longtai', 'liusong', 'zhaohuhu'], 'txt': Markup("<input type='text'/>"), 'func': func, } return render_template('tpl.html', **context) @app.route('/ses/') def ses(): print(type(session)) # <class 'werkzeug.local.LocalProxy'> session['k1'] = 123 session['k2'] = 456 del session['k1'] return "Session!" @app.route('/page1/') def page1(): flash("cuixiaozhao19930911!", 'error') flash("临时存储数据!", 'info') flash("临时存储数据!", 'warning') # session['uuu'] = 123 return "Session uuu123!" @app.route('/page2/') def page2(): # print(session['uuu']) print(get_flashed_messages(category_filter=['error'])) return "Session uuu456!" def func(arg): return arg + 1 @app.template_global() def sb(a1, a2): return a1 + a2 @app.template_filter() def db(a1, a2, a3): return a1 + a2 + a3 # {{ 1|db(1800,92) }} if __name__ == '__main__': app.run()
12 Flask框架:中间件
12.1 聊一下Flask的源码;
12.2 Flask中的中间件说明,使用场景较少,一般通过装饰器来做;
from flask import Flask, render_template, redirect, request, session, url_for, make_response, Markup, flash, \ get_flashed_messages app = Flask(__name__) @app.route('/index/') def index(): print('index') return "Index" class Middleware(object): def __int__(self, old): self.old = old def __call__(self, *args, **kwargs): ret = self.old(*args, **kwargs) return ret if __name__ == '__main__': app.wsgi_app = Middleware(app.wsgi_app) app.run()
13 Flask框架:特殊装饰器(非常重要)
- before_request
- after_request
- before_first_request
- after_first_request
- template_global
- template_filter
- errorhandler(404),应用非常广泛!
14 今日内容总结
14.1 配置文件;
14.2 路由;
14.3 但凡写装饰器,都要加上 functools;
14.4 视图FBV;Django以参数传输,Flask导入;
14.5 请求和响应;
14.6 模板——继承、include、自定义函数、特殊的装饰器(global)、语法更接近Python;
14.7 session和flash(闪现)以加密的形式存储在用户的token中,默认session的超时时间是31天,Django是2周的时长;
14.8 中间件和特殊的装饰器;__call__方法来做;
14.9 6个装饰器;