一.应用的基本结构 1.路由: (1)处理URL和函数之间的关系的程序,实现通过一个URL调用某个函数的功能 可以通过app.url_map查看所有url与函数映射. (2)通常使用app.route装饰路由,有时也可以使用app.add_url_rule("/",'index',index) 一个最为简单的flask实例 from flask import Flask app = Flask(__name__) @app.route("/") def index(): return render_template("index.html") if __name__ == '__main__': app.run(debug=True) (3)flask支持动态URL,利用/<type:value> type是类型,value是参数名 @app.route("/name=<string:name>") def get_name(name): print(name) return render_template("index.html") type:int,float,path,string path和string的不同,是path可以包含正斜线 (4)路由的返回值称为响应,即通过访问URL,flask对该行为做出的处理 2.命令行选项: (1)flask run --host 启动服务器 (2)flask --help 查看flask的选项 (3)shell用处:可以在应用上下文打开一个Python shell的会话,在这个会话中可以运行维护任务和调试 3.调试模式: (1)Flask应用可以在调试模式中运行,服务器会默认加载重载器和调试器. 重载器:Flask会监视项目中所有源码文件,但文件发生变动保存,会自动重启服务器 调试器:当应用抛出未处理的异常时。web浏览器变成一个交互式的栈跟踪,可以在浏览器查看源码,查看异常出现的位置 (2)在shell中实现 export FLASK_APP=app.py export FLASK_DEBUG=1 flask run 这样就为debug模式了 (3)在代码中实现app.run(debug=True) (4)生产服务器千万不要开启调试模式!!!! 4.应用和请求上下文: 当客户端发送一个请求的时候,此时服务端需要访问客户端的一些信息,这样才能更好的对这个请求做出相应的响应 此时就可以使用的应用和请求上下文(如果没有的话,每次请求都要携带参数,会让代码变成糟糕) flask使用上下文就临时把某些对象变成全局可访问,该全局是对于某个线程而言,对于整个服务器不可能为全局,因为当多个用户访问时,整个服务器会变得混乱 (1)分类: current_app 应用上下文 保存当前app相关信息 g 应用上下文 在同一次请求上下文中设置临时变量属性,供请求上下文使用 request 请求上下文 请求用户,访问发送http请求的内容 session 请求上下文 记录会话,以键值对的字典数据类型 (2)获取应用上下文的方法是在应用实例上调用app.app_context() 之后就可以访问current_app的属性和方法,current_app实则是app的一个备份 current_app.name访问当前app的名称 (3)g对象的使用 class Student: def __init__(self,student_id,name): self.student_id = student_id self.name = name stu1 = Student(1,"小A") @app.route('/') def index(): # print(current_app.name) g.student_id = stu1.student_id g.name = stu1.name return redirect(url_for("_redirect")) @app.route('/_redirect') def _redirect(): return f"hello {g.name}!Your student id is {g.student_id}" 上面代码看起来,好像非常合理。但是运行起来会出现:AttributeError: '_AppCtxGlobals' object has no attribute 'name' 什么原因呢?因为redirect重定向相当于重新发送了一次请求,但是g对象保存的数据的生命周期仅仅在同一次请求中生效. 正确使用方式: @app.route('/') def index(): g.student_id = stu1.student_id g.name = stu1.name print_content() return "hello" def print_content(): print(f"hello {g.name}!Your student id is {g.student_id}") (4)请求对象: form 一个字典,存储请求提交的所有表单字段 args 一个字典,存储通过URL查询字符串传递的所有参数 values 一个字典form和args的合集 cookies 一个字典,存储请求的所有cookie headers 一个字典,存储请求的所有http的headers files 一个字典,存储请求上传的所有文件 get_json 返回一个Python字典 method http请求方法 remote_addr 客户端的IP地址 (5)session: 使用之前需要设置一个key,因为flask会将session进行加密存储在cookie中 app.config["SECRET_KEY"] = "your key" session["name"] = name 将name存储在session中,需要使用直接session.get("name") 5.请求钩子 在请求发送前或之后执行的代码 常用于身份校验,日志,数据库连接 before_request 注册一个函数,在每次请求之前运行 before_first_request 注册一个函数,只在处理第一个请求之前运行。可以通过这个钩子添加服务器初始化任务 after_request 注册一个函数,如果没有抛出异常,在每次请求之后运行 teardown_request 注册一个函数,即使有未处理的异常抛出,在每次请求之后运行 请求钩子与视图函数之间,通常在请求钩子的函数使用g临时变量来存储对象,之后在视图函数就可以使用g这个临时对象 实例测试: from flask import Flask, g app = Flask(__name__) @app.before_first_request def bfr(): print("before_first_request") @app.before_request def bf(): print("before_request") @app.after_request # 这边最少要有一个参数(其实是响应)为,且函数需要返回这个参数作为响应 def ar(arg): print("after_request") return arg @app.teardown_request # 这边最少要有一个参数(其实是响应)为,且函数需要返回这个参数作为响应 def tr(arg): print("teardown_request") return arg @app.route('/') def index(): return "hello" if __name__ == '__main__': app.run() 先访问页面后刷新一次,后端打印结果: before_first_request before_request after_request teardown_request before_request after_request teardown_request 和我们预期的数据一致 6.响应 flask每次调用视图函数后,都应该返回一个响应给客户端,视图函数返回值就是对客户端的响应。 响应可以是html页面,字符串,或者Json字典返回给前端 (1)状态码 但是http请求还要返回状态码,flask默认200,表示请求在后端成功处理。 设置状态码 return "<h1>Bad Request<h1>",404 (2)返回一个响应对象 使用make_response函数,创建一个resp对象: resp = make_response("index.html") 响应对象常用属性和方法 status_code http状态码 headers 响应头 set_cookie 为响应添加一个cookie get_data 获取响应主体 resp.set_cookie("answer","42") (3)重定向 重定向状态码通常为302 使用redirect进行重定向 (4)异常抛出 abort(404) 二.模板 一个优秀的应用应该处理好业务逻辑和表现逻辑。 这边业务逻辑大多数指后端,表现逻辑指的是前端,而模板的使用主要是处理前端页面的渲染 模板是包含响应文本的文件,包含用占位符变量表示的动态部分,其具体值由请求服务端得到的数据,进行对页面的渲染 1.jinja2模板引擎 (1)渲染模板 from flask import Flask app = Flask(__name__) @app.route("/") def index(): return render_template("index.html",arg=arg) 终端flask run启动程序 render_template()第一个参数为模板名称,其后就是参数都是键值对. 默认情况下,flask会到templates去寻找index.html (2)变量 在模板中使用{{ arg }}表示一个变量,这是一个占位符,告诉jinja2这个需要渲染的值是从服务端获得的 jinja2可以识别所有类型的变量,包括对象,字典,列表,元组...... 过滤器:形如{{ arg|capitalize }} 常用过滤器: safe 渲染值时不转义 capitalize 把首字母转换为大写,其它字母转换为小写 lower 把值转化成小写形式 upper 把值转化为大写形式 title 把值中每个单词的首字母都转换成大写 千万不要在不可信的数据上使用safe过滤器 (3)基础语法 if语句 {% if %} 1 {% else %} 2 {% endif %} for循环 {% for comment in comments %} {{ comment }} {% endfor %} 宏(类似于函数) 基本没有用,这边就不详细说了,需要了解阅读p23 重点:继承,类似于python中的继承,先写一个base,然后其它需要使用该模板的部分或者全部内容的模板可以进行extend 这样就可以省去许多冗余的代码. 基模板可以定义区块,衍生模板可以对该内容进行覆盖,或者super()后加上其它需求 jinja2使用block和endblock在基模板中定义内容区块(进行占位),后续在衍生类只需在占位区块填入数据即可 base.html <!DOCTYPE html> <html lang="en"> <head> {% block head %} <meta charset="UTF-8"> <title>{% block title %} {% endblock %} -My Application</title> {% endblock %} </head> <body> {% block body %} {% endblock %} </body> </html> extends.html {% extends "base.html" %} {% block title %}Welcome{% endblock %} {% block head %} {{ super() }} <style> </style> {% endblock %} {% block body %} <h1>Hello<h1> {% endblock %} 2.flask-bootstrap 在app中进行Bootstrap实例化后,在模板中继承bootstrap.html后,就能在模板中使用模板语法调用bs. 3.自定义错误页面 与视图函数一样,自定义错误函数,要对客户端做出响应 优点:自定义错误页面可以给用户更好的页面效果和体验 main.py @app.errorhandler(404) def page_not_found(e): return render_template("404.html"),404 @app.errorhandler(500) def internal_server_error(e): return render_template("500.html"),500 上面捕获了404,500两种http状态码 这边可以结合前面的abort(404)结合使用,抛出异常,然后捕获异常 404.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>页面走丢了</title> </head> <body> <h1>页面走丢了</h1> </body> </html> 500.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>error</title> </head> <body> <h1>出错了</h1> </body> </html> 4.链接: url_for() flask可以提供了可以通过函数名称访问该函数对于的url url_for("index",name="abc",id="123) 第一个参数为函数名称,后面为键值对参数,使用起来与render_template类似 print(url_for("index")) 可以得到/,即根路径 后端向后端传递 @app.route("/") def index(): return redirect(url_for('show_data',name="Titans",age=20)) @app.route('/url_for?name=<name>&age=<int:age>') def show_data(name,age): return f"{name}'age is {age}" 前端向后端传递 {{ url_for("show_data",name="Titans",age=20) }} 5.访问静态文件 在app.url_map可以查看到有一个/static/<filename> 这是flask为了支持静态文件自动添加了一个路径 因此可以通过url_for("static",filename="abc.png") 6.使用Moment本地化日期和时间 后端: from flask_moment import Moment from datetime import datetime ...... moment = Moment(app) @app.route('/') def hello_world(): return render_template('extends.html',current_time=datetime.utcnow()) 前端: {% extends "bootstrap/base.html" %} {% block title %} 本地化日期和时间 {% endblock %} {% block head %} {{ super() }} {{ moment.include_moment() }} {% endblock %} {% block body %} <p>The local date and time is{{ moment(current_time).format('LLL') }}.</p> <p>That was {{ moment(current_time).fromNow(refresh=True) }}</p> {% endblock %}
Flask狗书学习笔记(上)
于 2022-06-02 20:28:13 首次发布