Как выбрать только некоторые из столбцов из базы данных с Flask-SQLAlchemy? - PullRequest
0 голосов
/ 11 апреля 2019

Я разрабатываю API с flask_restplus и flask_sqlalchemy, и у меня есть особый случай, когда определенные приложения должны получать доступ только к определенным столбцам из 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)

Я также указал flask_resplus 'модель, которая будет возвращена из API:

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

Где api - это экземпляр flask_restplus' Api и dbflask_sqlachmey экземпляр.

Иногда я хочу выбрать только некоторые из столбцов, а другой столбец будет null в api.model, который возвращается как ответ JSON.

После поиска в Интернете я нашел два метода, которые ни один из них не работает в моем случае: load_only() из sqlalchemy.orm, который возвращает столбцы как list.В результате я не могу вернуть эти результаты, так как моя модель ожидает словарь с такими же ключами, как описано в my_model.Другой метод, with_entities(), возвращает экземпляр MyModel, что мне и нужно, но он загружает все столбцы в тот момент, когда я передаю этот экземпляр в my_model, поскольку он выполняет только отложенный выбор, т.е.выбирает указанные столбцы, но если требуются другие столбцы, он снова выполняет запрос, чтобы получить значения других столбцов, таким образом загружая, в моем случае, все столбцы, а это не то, что мне нужно.Кто-нибудь знает, как сделать SQL SELECT, когда возвращаются только некоторые из столбцов, а результат является экземпляром db.Model?

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 16 июня 2019

Если вы используете 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 схемы Marshmallow, где есть несколько вариантов, включая исключение всего списка, например: https://marshmallow.readthedocs.io/en/latest/api_reference.html#marshmallow.Schema

1 голос
/ 11 апреля 2019

Вы можете использовать маскировку поля в 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)

...