Reputation: 149
I have something like this:
{
"id": 1,
"username": "plasmy",
"userdetails": [
{
"detail": "A Name",
"detail_name": "Full Name",
"id": 1,
"user_id": 1
},
{
"detail": "[email protected]",
"detail_name": "Email",
"id": 2,
"user_id": 1
},
{
"detail": "An Address",
"detail_name": "Address",
"id": 3,
"user_id": 1
},
{
"detail": "999-999-9999",
"detail_name": "Phone Number",
"id": 4,
"user_id": 1
}
]
}
This comes as a result from using Flask_Restless and SQLAlchemy. There is a table for users and a table for userdetails, which are put in the userdetails part of that JSON. What I want to do is, find a way in which the data can look like this:
{
"id": 1,
"username": "plasmy",
"userdetails": {
"Full Name": "A Name",
"Email": "[email protected]",
"Address": "An Address",
"Phone Number": "A Phone Number"
}
}
See how I removed the ids and I used the field "detail_name" as the key and "detail" as value. I tried using preprocessors but they didn't work or maybe I'm using them wrong. I put the preprocessor in the "child" table.
This is what I tried doing (but didn't work):
def detail_sort(results):
return {'user_details': results['userdetails']}
manager.create_api(User, methods=['GET', 'POST'])
manager.create_api(UserDetails, methods=['GET', 'POST'],
preprocessors={
'GET_COLLECTION': [detail_sort]
})
I tried GET_COLLECTION, GET_SINGLE and GET_MANY. Any help on this will be greatly appreciated.
UPDATE: Here is the new code I tried based on the answer
from flask import Blueprint
from medinv import manager
from medinv.User.models import User, UserDetails
blueprint = Blueprint('blueprint', __name__)
@blueprint.route('/')
@blueprint.route('/home')
def home():
return "Welcome."
def detail_sort(results):
print(results)
results['userdetails'] = {item['detail_name']: item['detail'] for item in results['userdetails']}
return results['userdetails']
manager.create_api(User, methods=['GET', 'POST'])
manager.create_api(UserDetails, methods=['GET', 'POST'],
postprocessors={
'GET_COLLECTION': [detail_sort]
})
Upvotes: 3
Views: 388
Reputation: 6053
I think you need to use postproccessors since you need to modify the json response before sending it back to the client.
OK, I reproduced your problem. Now it's working. Here is my code:
import flask
import flask_sqlalchemy
import flask_restless
# Create the Flask application and the Flask-SQLAlchemy object.
app = flask.Flask(__name__)
app.config['DEBUG'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = flask_sqlalchemy.SQLAlchemy(app)
# Create your Flask-SQLALchemy models as usual but with the following
# restriction: they must have an __init__ method that accepts keyword
# arguments for all columns (the constructor in
# flask_sqlalchemy.SQLAlchemy.Model supplies such a method, so you
# don't need to declare a new one).
class User(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String)
userdetails = db.relationship('UserDetails', backref='User', lazy='dynamic')
class UserDetails(db.Model):
__tablename__ = 'user_details'
id = db.Column(db.Integer, primary_key=True)
detail = db.Column(db.String)
detail_name = db.Column(db.String)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)
# Create the database tables.
db.create_all()
# Create the Flask-Restless API manager.
manager = flask_restless.APIManager(app, flask_sqlalchemy_db=db)
user = User(username='plasmy')
userdetail_0 = UserDetails(detail='A name', detail_name='Full Name' )
userdetail_1 = UserDetails(detail='[email protected]', detail_name='Email')
userdetail_2 = UserDetails(detail='An Address', detail_name='Address')
userdetail_3 = UserDetails(detail='999-999-9999', detail_name='Phone Number')
user.userdetails.append(userdetail_0)
user.userdetails.append(userdetail_1)
user.userdetails.append(userdetail_2)
user.userdetails.append(userdetail_3)
db.session.add(user)
db.session.commit()
print('USER CREATED')
def detail_sort(result, **kw):
print('detail_sort called')
print(result)
for entry in result['objects']:
entry['userdetails'] = {item['detail_name']: item['detail'] for item in
entry['userdetails']}
print('MODIFIED JSON: ', result)
# Create API endpoints, which will be available at /api/<tablename> by
# default. Allowed HTTP methods can be specified as well.
# manager.create_api(Person, methods=['GET', 'POST', 'DELETE'])
# manager.create_api(Article, methods=['GET'])
manager.create_api(User, methods=['GET', 'POST', 'DELETE'],
postprocessors={
'GET_MANY': [detail_sort]
})
manager.create_api(UserDetails, methods=['GET'], )
# start the flask loop
app.run(use_reloader=False)
Note that you need to use GET_MANY
and look how detail_sort
is implemented.
Without using postprocessor the response is like this:
{
"num_results": 1,
"objects": [
{
"id": 1,
"userdetails": [
{
"detail": "A name",
"detail_name": "Full Name",
"id": 1,
"user_id": 1
},
{
"detail": "[email protected]",
"detail_name": "Email",
"id": 2,
"user_id": 1
},
{
"detail": "An Address",
"detail_name": "Address",
"id": 3,
"user_id": 1
},
{
"detail": "999-999-9999",
"detail_name": "Phone Number",
"id": 4,
"user_id": 1
}
],
"username": "plasmy"
}
],
"page": 1,
"total_pages": 1
}
With postprocessor the response looks like this:
{
"num_results": 1,
"objects": [
{
"id": 1,
"userdetails": {
"Address": "An Address",
"Email": "[email protected]",
"Full Name": "A name",
"Phone Number": "999-999-9999"
},
"username": "plasmy"
}
],
"page": 1,
"total_pages": 1
}
Hope this helps.
Upvotes: 3