如何使用Flask-SQLAlchemy从数据库中仅选择某些列?

时间:2019-04-11 14:17:26

标签: python flask sqlalchemy flask-sqlalchemy

我正在使用flask_restplusflask_sqlalchemy开发API,但我有一个特殊情况,即某些应用程序应仅访问API中的某些列。

我有一个模特:

class MyModel(db.Model):
    __tablename_ = 'my_table'
    id = db.Column(db.Integer, primary_key=True)
    first_column = db.Column(db.Unicode)
    second_column = db.Column(db.Unicode)

我还指定了要从API返回的flask_resplus'模型:

my_model = api.model('MyModel',
                    {'first_column': fields.String(),
                     'second_column': fields.String()})

其中apiflask_restplus'Api的实例,dbflask_sqlachmey的实例。

有时候,我只想选择一些列,而另一列要作为以JSON响应返回的null中的api.model

在Internet上搜索后,我发现两种方法都不适合我的情况: load_only()中的sqlalchemy.orm,将列返回为list。结果,我无法返回这些结果,因为我的模型期望字典具有与my_model中所述相同的键。另一种方法with_entities()返回我需要的MyModel实例,但是在我将该实例传递给my_model时它会加载所有列,因为它只会惰性选择,即它选择指定的列,但是如果需要其他列,它会再次执行查询以获取其他列的值,因此在我的情况下,加载所有列,这不是我想要的。 有人知道如何做SQL SELECT,其中仅返回一些列,结果是db.Model的实例?

提前谢谢!

2 个答案:

答案 0 :(得分:1)

您可以在flask-restplus中使用“字段屏蔽”来仅访问所需的字段。

签出此链接:https://flask-restplus.readthedocs.io/en/stable/mask.html

curl -X GET "http://localhost:5000/mymodel" -H  "accept: application/json" -H  "X-Fields: first_column"
from flask import Flask
from flask_restplus import Resource, Api
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer, String
import os
from flask_restplus import Resource, fields

basedir = os.path.abspath(os.path.dirname(__file__))

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{0}/app-dev.db'.format(
    basedir)
app.config['SECRET_KEY'] = '\xa4?\xca`\xa4~zG\xdf\xdbh\xba\xc2\xc6\xfc\x88\xc6x"\x11\xe8X8\n'

db = SQLAlchemy(app)
api = Api(app)


class MyModel(db.Model):
    __tablename_ = 'my_table'
    id = db.Column(db.Integer, primary_key=True)
    first_column = db.Column(db.String(255))
    second_column = db.Column(db.String(255))


my_model = api.model('MyModel',
                     {'first_column': fields.String(),
                      'second_column': fields.String()})


@api.route('/mymodel')
class GetModel(Resource):
    @api.marshal_with(my_model, envelope='resource', mask='first_column')
    def get(self, **kwargs):
        return MyModel.query.all()  # Some function that queries the db


@api.route('/hello')
class HelloWorld(Resource):
    def get(self):
        return {'hello': 'world'}


if __name__ == '__main__':
    db.drop_all()
    db.create_all()
    model1 = MyModel(first_column='m1_first', second_column='M1_SECOND')
    model2 = MyModel(first_column='m2_first', second_column='M2_SECOND')
    db.session.add(model1)
    db.session.add(model2)
    db.session.commit()
    app.run(debug=True)

答案 1 :(得分:1)

如果使用flask-marshmallow进行序列化,则可以使用包含(only())或排除(load_only())字段的列表加载架构。

因此,您可以粗略地模拟上面的内容:

from flask_sqlalchemy import SQLAlchemy
from flask_marshmallow import Marshmallow

db = SQLAlchemy()
ma = Marshmallow()

class MyModel(db.Model):
    __tablename_ = 'my_table'
    id = db.Column(db.Integer, primary_key=True)
    first_column = db.Column(db.Unicode)
    second_column = db.Column(db.Unicode)


class MyModelSchema(ma.ModelSchema):
    class Meta:
        model = MyModel

varlist = ['id','first_column']

def somefunction():
    results = MyModel.query.all()
    mymodelschema = MyModelSchema(many=True, only=varlist)
    output = mymodelschema.dump(results).data
    return jsonify(output) # or whatever you're doing with it

以下是棉花糖模式API的文档,其中有一些选项,包括排除列表中的所有内容,例如:https://marshmallow.readthedocs.io/en/latest/api_reference.html#marshmallow.Schema