I'm developing an API with flask_restplus
and flask_sqlalchemy
, and I have a special case where certain applications should access only certain columns from the API.
I have a model:
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)
I also have specified a flask_resplus
' model to be returned from the API:
my_model = api.model('MyModel',
{'first_column': fields.String(),
'second_column': fields.String()})
Where api
is a flask_restplus
' Api
instance and db
a flask_sqlachmey
's instance.
Sometimes I want to select only some of the columns, and for the other column to be null
in the api.model
that is returned as a JSON repsonse.
After searching on the Internet, I found two methods which neither of them work in my case: load_only()
from sqlalchemy.orm
, which returns the columns as a list
. As a result, I can't return those results, since my model expects a dictionary with same keys as described in my_model
. The other method, with_entities()
returns an instance of MyModel
, which is what I need, but it loads all the columns at the time I pass that instance to the my_model
, since it does only a lazy selection, ie it selects the specified columns, but if the other columns are required, it does a query again to get the values of other columns, thus loading, in my case, all the columns, which is not what I want. Does anyone know how to do an SQL SELECT
where only some of the columns are returned and the result is an instance of the db.Model
?
Thank you in advance!
If you use flask-marshmallow for serialization, you can load the schema with a list of included ( only()
) or excluded ( load_only()
) fields.
So a rough mock-up with what you've got above:
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
Here are the docs for the Marshmallow Schema API where there are a few options including excluding everything in a list, for example: https://marshmallow.readthedocs.io/en/latest/api_reference.html#marshmallow.Schema
You can use Field Masking in flask-restplus to access only the field you want.
Check Out this link: 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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.