Flask: Converting Python dict to json object for client api
Generally is a bad idea your approach on jsonifying a model:
self.__dict__
may contain a lot of undocumented keys- column types: you can't jsonify
relationship
and column types directly. And notably adatetime
column. - security: sometimes you might want to hide some fields (for untrusted users consuming your APIs for example)
A good approach is to create a method to return a json serializable dictionary:
class Foo(db.Model):
field1 = db.Column(...)
field2 = db.Column(...)
def as_dict(self):
obj_d = {
'field1': self.field1,
'field2': self.field2,
...
}
return obj_d
Then in your view:
foos = Foo.query.all()
results = [ foo.as_dict() for foo in foos ]
return jsonify({count: len(results), results: results)
Based on your application you can make as_dict
smarter by converting fields (notably datetime fileds) in javascript friendly formats or adding convenient fields like following a relationship.
user2957824
Updated on June 05, 2022Comments
-
user2957824 almost 2 years
I need to create a json object from a flask a query result. I then need to pass the json object to the route to create an API.
In searching for some slick ways to create dicts from my instances I stumbled upon a method in this post to use the internal dict of the instance and add a jsond method to the model class. Here is the Model with the custom method, 'jsond':
from app import db class Rest(db.Model): id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(100), unique = True) street = db.Column(db.Text) zipcd = db.Column(db.Integer) comments = db.relationship('Comment', backref='rest', lazy='dynamic') lat = db.Column(db.Float(6)) lng = db.Column(db.Float(6)) def __init__(self,name,street,zipcd): self.name = name self.street = street self.zipcd = zipcd def __repr__(self): return '{}'.format(self.name) def name_slug(self): return self.name def jsond(self): instDict = self.__dict__.copy() if instDict.has_key('_sa_instance_state'): del instDict['_sa_instance_state'] return instDict
And here's my view function:
from app import app, db from flask import render_template, flash, redirect, session, url_for, request, g, jsonify, make_response from flask.json import dumps from flask.ext import restful from flask.ext.httpauth import HTTPBasicAuth from models import Comment, Rest, Badge from helper import make_badges, make_inspections, loc_query import operator auth = HTTPBasicAuth() @app.route('/api',methods=['GET']) def makeApi(): ###Query Parameters### lim = request.args.get('limit', 10) off = request.args.get('offset', 0) loc = request.args.get('location', "39.94106,-75.173192") lat, lng = loc.split(",") radius = request.args.get('radius',2) query = loc_query(lat,lng,radius,off,lim) results = Rest.query.from_statement(query).all() rest_json = [] for rest in results: rest_json.append(rest.jsond()) return make_response(jsonify({'count':len(rest_json),'rests':rest_json}))
So when in the python API command line I can run queries successfully and create a dict from a particular instances in a query with all fields present (using the custom jsond method). However when I go to the makeApi route using my view I get a json object with ONLY THE 'id' field present:
rests: [ { id: 28450 }, { id: 28795 }, { id: 30439 }, { id: 29325 }, { id: 29765 }, { id: 29928 }, { id: 30383 }, { id: 29064 }, { id: 29862 }, { id: 28610 } ] }
I've been going in circles for hours and have no idea why the view behavior would differ from the python API. Perhaps its something Im doing wrong with jsonify but i dont think so.
-
user2957824 about 10 years@paolocasiello is there way to pass a dict object for use in the template directly? if so is this ever beneficial?
-
Paolo Casciello about 10 yearsYou mean Jinja templates? You can pass the whole model to the templates
render_template(..., mod=model)
and use functions/attributes directly from the template -
qazimusab over 7 yearsThanks so much! This helped me a ton!