zoukankan      html  css  js  c++  java
  • flask基本使用方法及异常场景

    Flask本身相当于一个内核,Flask=Werkzeug+Jinja2

    falsk运行过程

    1.app.run() 执行了该方法后,就会将flask程序运行在一个简易web服务器(有flask提供)
    2.程序实例由werkzeug实现路由分发(url请求和视图函数之间的关系)。在flask中,路由的实现一般是通过程序实例的装饰器实现。
    3.flask调用视图函数后,可以返回两种内容

    • 字符串内容:将视图函数的返回值作为响应内容
    • html模板内容:获取到数据后,把数据传递给html模板文件,模板引擎负责渲染数据,然后返回响应数据给客户端

    路由请求方式限定
    @app.route('/',methods=['GET','POST']) #路由默认只支持get

    路由参数处理

    @app.route('/order/<int:order_id>')   #int会将输入的参数强制转为正型,成功方可请求成功
    def get_order_id(order_id):  #要传入形参方可在内部获取
      print(order_id)
    

    应用程序配置参数
    app.config 对象保存了flask的⼯程配置信息,当做字典。

    • 读取
      • app.config['SECRET_KEY']
      • app.config.get('SECRET_KEY')
    • 设置保存
      • app.config['SECRET_KEY'] =xxx
        批量设置
      • app.config.from_object(配置对象)
        • 优点,以类实现能够复用
        • 缺点,将敏感配置信息暴露在代码
      • app.config.from_pyfile(配置文件)
        • 优点,配置信息单独维护,一定程度保证了安全
        • 缺点,仍不安全,名字固定
      • app.config.from_envvar('环境变量名')
        - 环境变量,即由操作系统保存的变量数据
        - 本质上,由环境变量保存真实配置文件的路径,flask通过这个环境变量找到配置文件再加载。
        - 缺点使用麻烦

    响应
    模板:return render_template('index.html', my_str=xxx, my_int=xxx)
    重定向:return redirect('/index')
    json: return jsonify({}) ,响应体数据是json字符串,响应头Content-Type: application/json。

    cookie与session

    cookie

    • 设置
      resp = make_response()
      resp.set_cookie(cookie名,cookie值) 临时cookie
      resp.set_cookie(cookie名,cookie值,有效期)
    • 读取
      request.cookies.get(cookie名)
    • 清除
      resp=make_reponse()
      resp.delete_cookie(cookie名)

    session
    from flask import session
    需要提前设置SECRET_KEY

    • 设置 session['username'] = 'python'
    • 读取 session.get('username')
      session数据保存到哪了?
      flask 原⽣ client-side-session (session数据保存到了cookie中)
      cookie session: {'username': 'python'}

    异常处理

    异常终止
    abort()
    捕获错误
    @app.errorhandler(404)
    @app.errorhandler(ZeroDivisionError)

    请求钩子

    作⽤ 中间件

    • before_first_reques
    • before_request
    • after_request
    • teardown_request
      lask接收到请求之后的完整处理时序流程
      接收到第⼀个请求:
      -> before_first_request 提供的⽅法
      -> before_request 提供的⽅法
      -> 视图处理
      -> after_request 提供的⽅法(视图没有发⽣异常)
      -> teardown_request 提供的⽅法
      -> 返回给客户端

    接收以后的请求:
    -> before_request 提供的⽅法
    -> 视图处理
    -> after_request 提供的⽅法(视图没有发⽣异常)
    -> teardown_request 提供的⽅法
    -> 返回给客户端

    上下文

    request、 session 、 current_app 、 g。在flask程序的外部,⽐如 使⽤python终端进⾏调试 或者 ⾃⼰独⽴编写脚本 ,不能直接导⼊使⽤,需要为这4个对象 创建他们的上下⽂环境。

    • 创建应⽤上下⽂环境
      • with app.app_context()
    • 创建请求上下⽂环境
      • with app.request_context({})
    • 请求上下文
      • request
      • session
    • 应用上下文
      • current_app
      • g
        使用
    • current_app
      • from flask import current_app
      • current_app 就是flask app ( app = Flask(name) )的代理⼈可以简单理解为 current_app 等价于app
      • 应⽤场景: 在不⽅便使⽤app对象的时候,可以使⽤current_app代替
    • g(g对象 g变量)
      • from flask import g
      • 只是flask提供的临时保存数据的"仓库", flask在每次处理⼀个请求之前都会清理g对象
      • 保存的数据只对单次请求有效
      • 应⽤场景:在⼀次请求涉及调⽤的多个函数间传递参数

    认证机制

    • 对已经签发了身份信息的用户,之后的验证处理?
    • 特定视图 要求⽤户必须登录 : 装饰器
    • 所有视图 要修随时可以查询⽤户的身份 如果⽤户登录 user_id=xxx 如
    • 果⽤户未登录 user_id=None : 请求钩⼦ before_request

    ⽤户携带身份信息(session cookie jwt)发起了请求
    -> 请求钩⼦ before_request 判断⽤户的身份 如果登录 g.user_id=xxx 否
    则 g.user_id=None
    -> 如果是不强制登录的视图 进⼊视图内部执⾏ 想要获取⽤户身份的时候
    直接读取g.user_id
    如果是强制登录的视图(加了装饰器) -> 装饰器中 判断g.user_id is None 返
    回401 否则 进⼊视图执⾏

    Jinja2

    resp.delete_cookie(cookie名session

    jinja2是一个模板引擎,也是用python实现的模板语言。
    接口是render_template()函数
    return render_template('index.html',title='Home',user=user) 需要传入的值以键值对的方式传入

    变量代码块使用
    {{ 变量名 }}
    变量为列表时,通过点语法或者中括号方式获取子元素{{ myslit.2 }} ,{{ myslit[2] }} 获取列表中的第二个元素
    变量为字典时,通过{{ mydict.key1 }} ,{{ mydict[key1] }}方式获取

    控制代码块
    由{% %}控制的代码块

    过滤器
    过滤器的本质即函数,语法如下:变量名|过滤器
    {{ variable| filter_name(*args)}}

    表单处理之消息闪现
    flash()可传递消息给模板,模板中接收消息需要遍历
    视图函数中使用:flash(u'密码不一致')
    模板中使用:
    {% for message in get_falshed_messages() %}
    {{ message }}
    其中flask()在使用之前需要设置密钥,在app初始化后加入app.secret_key = 'xxx'

    数据库

    使用flask-sqlalchemy拓展

    • sqlalchemy是对数据库的抽象,使开发者可以不用和sql语句打交道,而是通过python对象来操作数据库。
    • sqlalchemy是一个关系型数据库框架,它提供了高层的ORM和底层的原生数据库的操作

    安装flask-sqlalchemy

    • pip install flask-sqlalchemy
    • 如链接mysql数据库,则还需安装mysqldb, pip install flask-mysqldb

    使用flask-sqlalchemy类型管理数据库

    • 在flask-sqlalchemy中,数据库通过URL指定,而且程序使用的数据库必须 保存到falsk配置对象的SQLALCHEMY_DATABASE_URI键中。

    Flask的数据库设置

    • app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:mysql@127.0.0.1:3306/test" (数据库连接设置,mysql为密码,test为数据库名。如未设置该选项则默认连接flask自带的sqlite)
    • app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False (动态修改追踪设置,如未设置则会显示警告,不建议开启)
    • app.config["SQLALCHEMY_ECHO"] = True (查询时会显示原始sql语句)

    常用sqlalchemy字段类型

    表格

    常用sqlalchemy列选项

    选项名 说明
    primary_key 如果为True,代表主键
    unique 如为True,代表不允许出现重复值
    index 如为True,为这列创建索引,提高查询效率
    nullable 如为True,允许有空值,
    default 为这列定义默认值

    代码示例

    from flask_sqlalchemy import SQLAlchemy
    app = Flask(__name__)
    
    app.config.from_object('config')
    app.config["SQLALCHEMY_DATABASE_URI"] = "mysql://root:@127.0.0.1:3306/flask_demo"
    app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = True
    db = SQLAlchemy(app)
    
    
    class User(db.Model):
        #定义表名
        __tablename__ = 'users'
        #定义字段
        id = db.Column(db.Integer, primary_key = True)
        nickname = db.Column(db.String(64), index = True, unique = True)
        email = db.Column(db.String(120), index = True, unique = True)
        posts = db.relationship('Post', backref='author', lazy='dynamic')
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key = True)
        body = db.Column(db.String(140))
        timestamp = db.Column(db.DateTime)
        user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    
        def __repr__(self):
            return '<Post %r>' % (self.body)
    

    数据库基本操作

    • 在flask-sqlalchemy中,插入,修改,删除操作,均由数据库会话管理。
      • 数据库会话由db.session表示。在将数据写入数据库前,要先将数据添加到会话中,然后调用commit()方法提交会话。
    • 在flask-sqlalchemy中,查询操作是通过query()对象操作数据
     db.session.add(role) 添加数据到session中
     db.session.add_all([user1,user2])
     db.session.delete(user) 删除数据库(需跟上commit) 
     db.session.commit() 提交数据库的修改(包括增删改)
     db.session.rollbask() 数据库的回滚操作
    

    模型之间的关联
    关键语句:
    posts = db.relationship('Post', backref='author', lazy='dynamic')

    class User(db.Model):
        # 定义表名
        __tablename__ = 'users'
        # 定义字段
        id = db.Column(db.Integer, primary_key=True)
        nickname = db.Column(db.String(64), index=True, unique=True)
        email = db.Column(db.String(120), index=True, unique=True)
        #关联Post模型,方便查询。给User模型增加了一个posts属性,其中backref='author'相当于给Post模型增加了一个author属性,为反向引用
        posts = db.relationship('Post', backref='author', lazy='dynamic')
        def __repr__(self):
            return '<User %r>' % (self.nickname)
    class Post(db.Model):
        id = db.Column(db.Integer, primary_key = True)
        body = db.Column(db.String(140))
        timestamp = db.Column(db.DateTime)
        user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
        def __repr__(self):
            return '<Post %r>' % (self.body)
    
    

    查询操作
    模型名.query.查询器 or 模型名.query.过滤器.查询器
    sqlalchemy查询过滤器

    过滤器 说明
    filter() 把过滤器添加到原查询上,返回一个新查询
    filter_by() 把等值过滤器添加到原查询上,返回一个新查询
    limit

    sqlalchemy查询执行器

    查询执行器 说明
    all() 以列表形式返回查询的所有结果
    first() 返回查询的第一个结果,未查询到则返回None
    first_or_404() 返回查询的第一个结果,未查询到则返回404
    get() 返回指定主键对应的行,未查询到则返回None
    get_or_404()
    count() 返回查询结果的数量

    1.警告内容:SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future. Set it to True or False to suppress this warning.
    解决方法:将config的SQLALCHEMY_TRACK_MODIFICATIONS设置为Ture或Flase即可

    2.if g.user is not None and g.user.is_authenticated():用法报错
    报错内容:TypeError: 'bool' object is not callable
    解决方法:is_authenticated是一个属性而不是一个方法,不可加小括号

  • 相关阅读:
    Android 通过ViewFlipper实现广告轮播功能并可以通过手势滑动进行广告切换
    [C#][DevPress]自定义数据分页控件
    [C#][SQLLITE]一个数据分页技巧
    [C#]用SharpZipLib压缩多个文件
    [C#][DevPress]省市县乡嵌套查询
    [C#][DevPress]事件委托的使用
    [C#]Excel操作类
    [C#][DevPress]手动添加控件中的子控件或者结构
    [C#]XML操作类
    [C#]把DataTable转换成泛型实体List
  • 原文地址:https://www.cnblogs.com/tingshu/p/14491352.html
Copyright © 2011-2022 走看看