플라스크에서 SQL 화학 결과를 jsonify화합니다.
플라스크/피톤으로 설정된 SQLAlchemy 결과를 jsonization하려고 합니다.
Flask 메일링 리스트는 다음과 같은 방법 http://librelist.com/browser/ /flask/2011/2/16/jsonify-sqalchemy-pag화-수집-result/#04a0754b63387f87dda564bde426e:
return jsonify(json_list = qryresult)
그러나 다음 오류를 반환합니다.
TypeError: <flaskext.sqlalchemy.BaseQuery object at 0x102c2df90>
is not JSON serializable
내가 여기서 뭘 간과하는 거지?
다음과 같은 질문을 발견했습니다.SqlAlchemy 결과를 JSON에 직렬화하는 방법은 무엇입니까? 매우 비슷해 보이지만 메일링 리스트 게시물이 제안한 것처럼 더 쉽게 만들 수 있는 마법이 플라스크에 있는지 몰랐습니다.
편집: 설명을 위해 모델의 모습은 이렇습니다.
class Rating(db.Model):
__tablename__ = 'rating'
id = db.Column(db.Integer, primary_key=True)
fullurl = db.Column(db.String())
url = db.Column(db.String())
comments = db.Column(db.Text)
overall = db.Column(db.Integer)
shipping = db.Column(db.Integer)
cost = db.Column(db.Integer)
honesty = db.Column(db.Integer)
communication = db.Column(db.Integer)
name = db.Column(db.String())
ipaddr = db.Column(db.String())
date = db.Column(db.String())
def __init__(self, fullurl, url, comments, overall, shipping, cost, honesty, communication, name, ipaddr, date):
self.fullurl = fullurl
self.url = url
self.comments = comments
self.overall = overall
self.shipping = shipping
self.cost = cost
self.honesty = honesty
self.communication = communication
self.name = name
self.ipaddr = ipaddr
self.date = date
쿼리를 실행하지 않은 것 같습니다.다음을 수행해 보십시오.
return jsonify(json_list = qryresult.all())
[편집]: jsonify의 문제점은 보통 객체를 자동으로 jsonify 할 수 없다는 것입니다.Python의 date time도 실패합니다 ;)
내가 과거에 한 일은 추가 재산을 추가하는 것입니다(예:serialize
직렬화가 필요한 클래스로 이동합니다.
def dump_datetime(value):
"""Deserialize datetime object into string form for JSON processing."""
if value is None:
return None
return [value.strftime("%Y-%m-%d"), value.strftime("%H:%M:%S")]
class Foo(db.Model):
# ... SQLAlchemy defs here..
def __init__(self, ...):
# self.foo = ...
pass
@property
def serialize(self):
"""Return object data in easily serializable format"""
return {
'id' : self.id,
'modified_at': dump_datetime(self.modified_at),
# This is an example how to deal with Many2Many relations
'many2many' : self.serialize_many2many
}
@property
def serialize_many2many(self):
"""
Return object's relations in easily serializable format.
NB! Calls many2many's serialize property.
"""
return [ item.serialize for item in self.many2many]
이제 뷰에 대해서는 다음과 같은 작업을 수행할 수 있습니다.
return jsonify(json_list=[i.serialize for i in qryresult.all()])
[2019 편집]:더 복잡한 객체나 원형 참조가 있는 경우 마시멜로와 같은 라이브러리를 사용합니다.
보통 제게 필요한 것은 다음과 같습니다.
저는 제 모델들과 함께 사용하는 직렬화 혼합물을 만듭니다.serialization 함수는 기본적으로 sqlchemy 검사자가 노출하는 속성을 가져와 dict에 넣습니다.
from sqlalchemy.inspection import inspect
class Serializer(object):
def serialize(self):
return {c: getattr(self, c) for c in inspect(self).attrs.keys()}
@staticmethod
def serialize_list(l):
return [m.serialize() for m in l]
이제 필요한 것은 SQLAlchemy 모델을 확장하는 것입니다.Serializer
수업 중에
노출하지 않으려는 필드가 있거나 특별한 서식이 필요한 필드는 간단히 덮어씁니다.serialize()
모델 하위 클래스의 함수입니다.
class User(db.Model, Serializer):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String)
password = db.Column(db.String)
# ...
def serialize(self):
d = Serializer.serialize(self)
del d['password']
return d
컨트롤러에서, 당신이 해야 할 일은serialize()
(또는n)serialize_list(l)
쿼리로 인해 목록이 생성되는 경우) 결과에 대한:
def get_user(id):
user = User.query.get(id)
return json.dumps(user.serialize())
def get_users():
users = User.query.all()
return json.dumps(User.serialize_list(users))
json으로 연재할 필요성이 있었어요이 질문을 보세요.열을 프로그래밍 방식으로 검색하는 방법을 보여줍니다.그래서 아래의 코드를 만들었습니다.그것은 저에게 효과가 있고, 저는 제 웹 앱에서 그것을 사용할 것입니다.
def to_json(inst, cls):
"""
Jsonify the sql alchemy query result.
"""
convert = dict()
# add your coversions for things like datetime's
# and what-not that aren't serializable.
d = dict()
for c in cls.__table__.columns:
v = getattr(inst, c.name)
if c.type in convert.keys() and v is not None:
try:
d[c.name] = convert[c.type](v)
except:
d[c.name] = "Error: Failed to covert using ", str(convert[c.type])
elif v is None:
d[c.name] = str()
else:
d[c.name] = v
return json.dumps(d)
class Person(base):
__tablename__ = 'person'
id = Column(Integer, Sequence('person_id_seq'), primary_key=True)
first_name = Column(Text)
last_name = Column(Text)
email = Column(Text)
@property
def json(self):
return to_json(self, self.__class__)
다음은 제 접근 방식입니다. https://github.com/n0nSmoker/SQLAlchemy-serializer
pip install SQLAlchemy-serializer
모델에 믹스인을 쉽게 추가한 다음 전화하기만 하면 됩니다..to_dict()
메소드(method)입니다.
다음을 기준으로 자신만의 믹스를 작성할 수도 있습니다.SerializerMixin
.
플랫 쿼리(가입 없음)의 경우 이 작업을 수행할 수 있습니다.
@app.route('/results/')
def results():
data = Table.query.all()
result = [d.__dict__ for d in data]
return jsonify(result=result)
데이터베이스에서 특정 열만 반환하려면 이 작업을 수행할 수 있습니다.
@app.route('/results/')
def results():
cols = ['id', 'url', 'shipping']
data = Table.query.all()
result = [{col: getattr(d, col) for col in cols} for d in data]
return jsonify(result=result)
좋아요, 몇 시간 동안 이 일을 해왔고, 제가 생각하기에 가장 피톤적인 해결책을 개발했습니다.다음 코드 조각은 python3이지만 필요하다면 백포트하기에 너무 고통스럽지는 않을 것입니다.
우리가 제일 먼저 할 일은 당신의 DB 모델들이 마치dict
s:
from sqlalchemy.inspection import inspect
class ModelMixin:
"""Provide dict-like interface to db.Model subclasses."""
def __getitem__(self, key):
"""Expose object attributes like dict values."""
return getattr(self, key)
def keys(self):
"""Identify what db columns we have."""
return inspect(self).attrs.keys()
이제 모델을 정의하고 믹스인을 이어받도록 하겠습니다.
class MyModel(db.Model, ModelMixin):
id = db.Column(db.Integer, primary_key=True)
foo = db.Column(...)
bar = db.Column(...)
# etc ...
여기까지만 하면 다음과 같은 예를 통과할 수 있습니다.MyModel()
.dict()
진정한 삶을 살 수 있는dict
예를 들어, 우리가 그것을 만드는 데 꽤나 많은 시간이 걸리게 합니다.jsonify()
이해합니다.다음으로, 우리는 연장해야 합니다.JSONEncoder
남은 길을 안내해 드리겠습니다
from flask.json import JSONEncoder
from contextlib import suppress
class MyJSONEncoder(JSONEncoder):
def default(self, obj):
# Optional: convert datetime objects to ISO format
with suppress(AttributeError):
return obj.isoformat()
return dict(obj)
app.json_encoder = MyJSONEncoder
보너스 포인트: 모델에 계산된 필드가 포함되어 있는 경우(즉, JSON 출력에 데이터베이스에 실제로 저장되지 않은 필드가 포함되기를 원하는 경우), 이 또한 쉽습니다.계산된 필드를 다음과 같이 정의합니다.@property
s, .keys()
방법은 다음과 같습니다.
class MyModel(db.Model, ModelMixin):
id = db.Column(db.Integer, primary_key=True)
foo = db.Column(...)
bar = db.Column(...)
@property
def computed_field(self):
return 'this value did not come from the db'
def keys(self):
return super().keys() + ['computed_field']
이제 jsonify를 하는 것은 사소한 일입니다.
@app.route('/whatever', methods=['GET'])
def whatever():
return jsonify(dict(results=MyModel.query.all()))
사용하시는 경우flask-restful
마샬을 사용할 수 있습니다.
from flask.ext.restful import Resource, fields, marshal
topic_fields = {
'title': fields.String,
'content': fields.String,
'uri': fields.Url('topic'),
'creator': fields.String,
'created': fields.DateTime(dt_format='rfc822')
}
class TopicListApi(Resource):
def get(self):
return {'topics': [marshal(topic, topic_fields) for topic in DbTopic.query.all()]}
당신은 당신이 무엇을 반환할 것인지, 어떤 종류인지 명시적으로 나열할 필요가 있습니다. 어쨌든 api는 제가 선호합니다.직렬화를 쉽게 처리할 수 있음(필요 없음)jsonify
), 날짜 또한 문제가 되지 않습니다.다음의 내용에 유의하십시오.uri
필드는 다음을 기반으로 자동으로 생성됩니다.topic
와 id.
선언 기반을 사용하는 경우(이미 게시된 답변 중 일부의 도움으로) 다음과 같이 답변합니다.
# in your models definition where you define and extend declarative_base()
from sqlalchemy.ext.declarative import declarative_base
...
Base = declarative_base()
Base.query = db_session.query_property()
...
# define a new class (call "Model" or whatever) with an as_dict() method defined
class Model():
def as_dict(self):
return { c.name: getattr(self, c.name) for c in self.__table__.columns }
# and extend both the Base and Model class in your model definition, e.g.
class Rating(Base, Model):
____tablename__ = 'rating'
id = db.Column(db.Integer, primary_key=True)
fullurl = db.Column(db.String())
url = db.Column(db.String())
comments = db.Column(db.Text)
...
# then after you query and have a resultset (rs) of ratings
rs = Rating.query.all()
# you can jsonify it with
s = json.dumps([r.as_dict() for r in rs], default=alchemyencoder)
print (s)
# or if you have a single row
r = Rating.query.first()
# you can jsonify it with
s = json.dumps(r.as_dict(), default=alchemyencoder)
# you will need this alchemyencoder where your are calling json.dumps to handle datetime and decimal format
# credit to Joonas @ http://codeandlife.com/2014/12/07/sqlalchemy-results-to-json-the-easy-way/
def alchemyencoder(obj):
"""JSON encoder function for SQLAlchemy special classes."""
if isinstance(obj, datetime.date):
return obj.isoformat()
elif isinstance(obj, decimal.Decimal):
return float(obj)
Flask-Restful
0.3.6
Request Parsing recommend 마시멜로
마시멜로(mashmallow)는 객체와 같은 복잡한 데이터 유형을 네이티브 파이썬 데이터 유형으로 변환하거나 변환하기 위한 ORM/ODM/프레임워크에 구애받지 않는 라이브러리입니다.
간단한 마시멜로우 예가 아래에 나와 있습니다.
from marshmallow import Schema, fields
class UserSchema(Schema):
name = fields.Str()
email = fields.Email()
created_at = fields.DateTime()
from marshmallow import pprint
user = User(name="Monty", email="monty@python.org")
schema = UserSchema()
result = schema.dump(user)
pprint(result)
# {"name": "Monty",
# "email": "monty@python.org",
# "created_at": "2014-08-17T14:54:16.049594+00:00"}
핵심 기능은 다음을 포함합니다.
스키마 선언하기
개체 직렬화("덤핑")
개체의 직렬화 해제("로딩")
객체 집합 취급
특성 이름 지정
직렬화/병렬화 키 지정
리팩토링:암시적 필드 만들기
주문 출력
"읽기 전용" 및 "쓰기 전용" 필드
기본 직렬화/병렬화 값 지정
네스팅 스키마
사용자 정의 필드
여기 모든 클래스에 as_dict() 메서드를 추가하는 방법과 모든 클래스에 대해 원하는 다른 메서드를 추가할 수 있습니다.이게 바람직한 방법인지 아닌지는 모르겠지만, 효과는 있습니다.
class Base(object):
def as_dict(self):
return dict((c.name,
getattr(self, c.name))
for c in self.__table__.columns)
Base = declarative_base(cls=Base)
저는 이 문제를 하루의 대부분 동안 살펴보았고, 제가 생각해낸 것은 다음과 같습니다(이 방향을 알려준 https://stackoverflow.com/a/5249214/196358 에 대한 크레딧).
(참고: 플라스크-sqalchemy를 사용하고 있기 때문에 모델 선언 형식이 스트레이트 sqalchemy와 조금 다릅니다.
나의models.py
파일:
import json
class Serializer(object):
__public__ = None
"Must be implemented by implementors"
def to_serializable_dict(self):
dict = {}
for public_key in self.__public__:
value = getattr(self, public_key)
if value:
dict[public_key] = value
return dict
class SWEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Serializer):
return obj.to_serializable_dict()
if isinstance(obj, (datetime)):
return obj.isoformat()
return json.JSONEncoder.default(self, obj)
def SWJsonify(*args, **kwargs):
return current_app.response_class(json.dumps(dict(*args, **kwargs), cls=SWEncoder, indent=None if request.is_xhr else 2), mimetype='application/json')
# stolen from https://github.com/mitsuhiko/flask/blob/master/flask/helpers.py
모든 모델 객체는 다음과 같습니다.
class User(db.Model, Serializer):
__public__ = ['id','username']
... field definitions ...
제가 보기에 저는 SWJsonnify로 전화를 걸었을 때 어디든 전화를 걸었습니다.Jsonify
, 다음과 같습니다.
@app.route('/posts')
def posts():
posts = Post.query.limit(PER_PAGE).all()
return SWJsonify({'posts':posts })
꽤 잘 작동하는 것 같군요.인간관계에서도 말입니다.아직 멀어진 것은 아니어서 YMMV이지만, 지금까지는 꽤 "맞다"는 느낌이 듭니다.
제안을 환영합니다.
ActiveRecord to_json에서 사용하는 레일 방식과 같은 것을 찾다가 다른 제안에 만족하지 못하고 이 Mixin을 사용하여 비슷한 것을 구현했습니다.중첩 모형을 처리하고 최상위 수준 또는 중첩 모형의 속성을 포함하거나 제외합니다.
class Serializer(object):
def serialize(self, include={}, exclude=[], only=[]):
serialized = {}
for key in inspect(self).attrs.keys():
to_be_serialized = True
value = getattr(self, key)
if key in exclude or (only and key not in only):
to_be_serialized = False
elif isinstance(value, BaseQuery):
to_be_serialized = False
if key in include:
to_be_serialized = True
nested_params = include.get(key, {})
value = [i.serialize(**nested_params) for i in value]
if to_be_serialized:
serialized[key] = value
return serialized
그런 다음 BaseQuery 직렬화 가능한 BaseQuery를 가져오려면 BaseQuery를 확장했습니다.
class SerializableBaseQuery(BaseQuery):
def serialize(self, include={}, exclude=[], only=[]):
return [m.serialize(include, exclude, only) for m in self]
다음 모델의 경우
class ContactInfo(db.Model, Serializer):
id = db.Column(db.Integer, primary_key=True)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
full_name = db.Column(db.String())
source = db.Column(db.String())
source_id = db.Column(db.String())
email_addresses = db.relationship('EmailAddress', backref='contact_info', lazy='dynamic')
phone_numbers = db.relationship('PhoneNumber', backref='contact_info', lazy='dynamic')
class EmailAddress(db.Model, Serializer):
id = db.Column(db.Integer, primary_key=True)
email_address = db.Column(db.String())
type = db.Column(db.String())
contact_info_id = db.Column(db.Integer, db.ForeignKey('contact_info.id'))
class PhoneNumber(db.Model, Serializer):
id = db.Column(db.Integer, primary_key=True)
phone_number = db.Column(db.String())
type = db.Column(db.String())
contact_info_id = db.Column(db.Integer, db.ForeignKey('contact_info.id'))
phone_numbers = db.relationship('Invite', backref='phone_number', lazy='dynamic')
당신이 할 수 있는 일은
@app.route("/contact/search", methods=['GET'])
def contact_search():
contact_name = request.args.get("name")
matching_contacts = ContactInfo.query.filter(ContactInfo.full_name.like("%{}%".format(contact_name)))
serialized_contact_info = matching_contacts.serialize(
include={
"phone_numbers" : {
"exclude" : ["contact_info", "contact_info_id"]
},
"email_addresses" : {
"exclude" : ["contact_info", "contact_info_id"]
}
}
)
return jsonify(serialized_contact_info)
jobDict라는 이름의 RowProxy 객체 목록의 sql query default dict를 사용하고 있었습니다. 객체의 Type이 무엇인지 알아내는 데 시간이 걸렸습니다.
이것은 행을 리스트에 캐스팅하고 dict를 처음에 리스트 값으로 정의하는 것만으로 깨끗한 jsonEncoding을 해결할 수 있는 정말 간단한 빠른 방법이었습니다.
jobDict = defaultdict(list)
def set_default(obj):
# trickyness needed here via import to know type
if isinstance(obj, RowProxy):
return list(obj)
raise TypeError
jsonEncoded = json.dumps(jobDict, default=set_default)
저는 이것을 하기 위해 제 방법을 추가하고 싶습니다.
db 모델을 serialize하기 위해 customjson 인코더를 정의하기만 하면 됩니다.
class ParentEncoder(json.JSONEncoder):
def default(self, obj):
# convert object to a dict
d = {}
if isinstance(obj, Parent):
return {"id": obj.id, "name": obj.name, 'children': list(obj.child)}
if isinstance(obj, Child):
return {"id": obj.id, "name": obj.name}
d.update(obj.__dict__)
return d
당신이 보기에 함수는
parents = Parent.query.all()
dat = json.dumps({"data": parents}, cls=ParentEncoder)
resp = Response(response=dat, status=200, mimetype="application/json")
return (resp)
부모님이 관계를 가지지만 잘 작동합니다.
많은 시간이 흘렀고 많은 유효한 답변이 있지만 다음 코드 블록이 작동하는 것 같습니다.
my_object = SqlAlchemyModel()
my_serializable_obj = my_object.__dict__
del my_serializable_obj["_sa_instance_state"]
print(jsonify(my_serializable_object))
이것이 완벽한 해결책도 아니고 다른 사람들처럼 우아하지도 않다는 것을 알고 있지만, 빠른 해결을 원하는 사람들은 이것을 시도해 볼 수 있습니다.
언급URL : https://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask
'programing' 카테고리의 다른 글
jQuery의 정규식 필드 유효성 검사 (0) | 2023.10.27 |
---|---|
휴대용 코드 - 문자당 비트 수 (0) | 2023.10.27 |
middle click (새 탭) 및 javascript 링크 (0) | 2023.10.27 |
Oracle-sql의 특정 열에서 전체 데이터 삭제 (0) | 2023.10.27 |
power(a,b) modn 계산하기 (0) | 2023.10.27 |