Flask狗书学习笔记(上)

一.应用的基本结构
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 %}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值