美文网首页咸的flaskPython
Flask 实现 Rest API (04) - 基于Flask

Flask 实现 Rest API (04) - 基于Flask

作者: Stone0823 | 来源:发表于2020-01-13 09:50 被阅读0次

    Flask 实现 Rest API (02) - 查询结果转换为 json 字符串 这篇文章中,介绍了基于原生 CRUD 将查询结果转为 json 格式的方法。本篇接着介绍使用 Flask-SqlAlchemy 时,如何将查询结果转换为 json 格式。过程是先将查询的结果转为 dict/list,然后将 dict/list 转为 json,dict/list 转 json 是 Python 内置的功能,所以关键在如何将 Python 对象转换为 dict/list。

    如果不使用第三方模块,需要手工编写代码来处理映射关系。假设在 MySQL 数据库中有一个 user 表,结构如下:


    如下代码实现了将所有用户信息通过 response 返回到客户端:

    from flask import Flask, jsonify
    from flask_sqlalchemy import SQLAlchemy
    import os
    from collections import OrderedDict
    
    app = Flask(__name__)
    
    # app.configurations
    app.config['SECURITY_KEY'] = 'you will never guess'
    app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URI']
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    app.config['JSON_SORT_KEYS'] = False
    
    db = SQLAlchemy(app)
    
    class User(db.Model):
        __tablename__ = 'user'
    
        USER_ID = db.Column(db.Integer, primary_key=True)
        USERNAME = db.Column(db.String(20))
        CREATED_BY = db.Column(db.String(20))
        CREATED_DATE = db.Column(db.Date)
    
    def user_to_dict(user):
        return OrderedDict(
            USER_ID = user.USER_ID,
            USERNAME = user.USERNAME,
            CREATED_BY = user.CREATED_BY,
            CREATED_DATE = user.CREATED_DATE
        )
    
    @app.route('/users')
    def list_users():
        users = User.query.all()
        return jsonify(list(map(user_to_dict, users)))
    
    @app.route('/users/<userid>')
    def find_user(userid):
        user = User.query.get(userid)
        return jsonify(user_to_dict(user))
    
    if __name__ == "__main__":
        app.run(debug=True)
    

    在本例中,user_to_dict() 函数实现了将 user 对象转换为 dict,但这种写法是硬编码的,有多少个 Model 就要写多少个函数,所以,我们接下来考虑如何实现通用的代码。

    对于 User 的实例,可以用 __dict__ 特殊属性获取实例的字段,为了通用化,将代码放在一个基类中:

    class EntityBase(object):
        def to_json(self):
            fields = self.__dict__
            if "_sa_instance_state" in fields:
                del fields["_sa_instance_state"]
            
            return fields
    

    然后在 Model 中通过多重继承,让 model 继承 EntitiBase 类,这样就不用改变每个 model 类的代码。为了方便叙述和学习,也给出第二种方法的完整代码:

    from flask import Flask, jsonify
    from flask_sqlalchemy import SQLAlchemy
    import os
    from collections import OrderedDict
    
    app = Flask(__name__)
    
    # application configurations
    app.config['SECURITY_KEY'] = 'you will never guess'
    app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URI']
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    app.config['JSON_SORT_KEYS'] = False
    
    db = SQLAlchemy(app)
    
    class EntityBase(object):
        def to_json(self):
            fields = self.__dict__
            if "_sa_instance_state" in fields:
                del fields["_sa_instance_state"]
            
            return fields
    
    class User(db.Model, EntityBase):
        __tablename__ = 'user'
    
        USER_ID = db.Column(db.Integer, primary_key=True)
        USERNAME = db.Column(db.String(20))
        CREATED_BY = db.Column(db.String(20))
        CREATED_DATE = db.Column(db.Date)
    
    @app.route('/users')
    def list_users():
        users = User.query.all()
        users_output = []
        for user in users:
            users_output.append(user.to_json())
        return jsonify(users_output)
    
    @app.route('/users/<userid>')
    def find_user(userid):
        user = User.query.get(userid)
        return jsonify(user.to_json())
    
    if __name__ == "__main__":
        app.run(debug=True)
    
    

    如果有多个表,并且有关联,以上方法需要更多的手工代码。比较好的方法是使用第三方模块:Flask-Marshmallow,这个也是我想推荐的方法。通过 pip 安装 Flask-Marshmallow 模块后,我们需要定义一个 UserSchema 类,并且确定 UserSchema 对应到 User,如下面的代码:

    from flask_marshmallow import Marshmallow
    
    ma = Marshmallow(app)
    
    class UserSchema(ma.ModelSchema):
        class Meta:
            model = User
    

    然后在路由中,可以方便的通过 dump() 方法转换为 dict。

    @app.route('/users')
    def list_users():
        users = User.query.all()
        user_schema = UserSchema(many=True)
    
        user_data = user_schema.dump(users).data
    
        return jsonify(user_data)
    
    
    @app.route('/users/<userid>')
    def find_user(userid):
        user = User.query.get(userid)
        user_schema = UserSchema()
    
        user_data = user_schema.dump(user).data
    
        return jsonify(user_data)
    

    完整代码如下:

    from flask import Flask, jsonify
    from flask_marshmallow import Marshmallow
    from flask_sqlalchemy import SQLAlchemy
    import os
    
    app = Flask(__name__)
    
    # application configurations
    app.config['SECURITY_KEY'] = 'you will never guess'
    app.config['SQLALCHEMY_DATABASE_URI'] = os.environ['DB_URI']
    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
    app.config['JSON_SORT_KEYS'] = False
    
    db = SQLAlchemy(app)
    ma = Marshmallow(app)
    
    class User(db.Model):
        __tablename__ = 'user'
    
        USER_ID = db.Column(db.Integer, primary_key=True)
        USERNAME = db.Column(db.String(20), nullable=False)
        CREATED_BY = db.Column(db.String(20), nullable=False)
        CREATED_DATE = db.Column(db.Date, nullable=False)
    
    class UserSchema(ma.ModelSchema):
        class Meta:
            model = User
    
    @app.route('/users')
    def list_users():
        users = User.query.all()
        user_schema = UserSchema(many=True)
    
        user_data = user_schema.dump(users).data
    
        return jsonify(user_data)
    
    @app.route('/users/<userid>')
    def find_user(userid):
        user = User.query.get(userid)
        user_schema = UserSchema()
    
        user_data = user_schema.dump(user).data
    
        return jsonify(user_data)
    
    if __name__ == "__main__":
        app.run(debug=True)
    

    源码

    源码放在 github 上。

    参考

    相关文章

      网友评论

        本文标题:Flask 实现 Rest API (04) - 基于Flask

        本文链接:https://www.haomeiwen.com/subject/ctjgactx.html