Một triển khai căn hộ
Bạn có thể sử dụng một cái gì đó như thế này:
from sqlalchemy.ext.declarative import DeclarativeMeta
class AlchemyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj.__class__, DeclarativeMeta):
# an SQLAlchemy class
fields = {}
for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
data = obj.__getattribute__(field)
try:
json.dumps(data) # this will fail on non-encodable values, like other classes
fields[field] = data
except TypeError:
fields[field] = None
# a json-encodable dict
return fields
return json.JSONEncoder.default(self, obj)
và sau đó chuyển đổi sang JSON bằng cách sử dụng:
c = YourAlchemyClass()
print json.dumps(c, cls=AlchemyEncoder)
Nó sẽ bỏ qua các trường không được mã hóa (đặt chúng thành 'Không').
Nó không tự động mở rộng quan hệ (vì điều này có thể dẫn đến tự tham chiếu và lặp lại mãi mãi).
Thực hiện đệ quy, không tuần hoàn
Tuy nhiên, nếu bạn muốn lặp lại mãi mãi, bạn có thể sử dụng:
from sqlalchemy.ext.declarative import DeclarativeMeta
def new_alchemy_encoder():
_visited_objs = []
class AlchemyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj.__class__, DeclarativeMeta):
# don't re-visit self
if obj in _visited_objs:
return None
_visited_objs.append(obj)
# an SQLAlchemy class
fields = {}
for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
fields[field] = obj.__getattribute__(field)
# a json-encodable dict
return fields
return json.JSONEncoder.default(self, obj)
return AlchemyEncoder
Và sau đó mã hóa các đối tượng bằng cách sử dụng:
print json.dumps(e, cls=new_alchemy_encoder(), check_circular=False)
Điều này sẽ mã hóa tất cả trẻ em, và tất cả trẻ em của chúng, và tất cả trẻ em của chúng ... Về cơ bản, mã hóa toàn bộ cơ sở dữ liệu của bạn. Khi nó đạt được thứ gì đó được mã hóa trước đó, nó sẽ mã hóa thành 'Không'.
Một cách thực hiện đệ quy, có thể thông tư, chọn lọc
Một cách khác, có lẽ tốt hơn, là có thể chỉ định các trường bạn muốn mở rộng:
def new_alchemy_encoder(revisit_self = False, fields_to_expand = []):
_visited_objs = []
class AlchemyEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj.__class__, DeclarativeMeta):
# don't re-visit self
if revisit_self:
if obj in _visited_objs:
return None
_visited_objs.append(obj)
# go through each field in this SQLalchemy class
fields = {}
for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
val = obj.__getattribute__(field)
# is this field another SQLalchemy object, or a list of SQLalchemy objects?
if isinstance(val.__class__, DeclarativeMeta) or (isinstance(val, list) and len(val) > 0 and isinstance(val[0].__class__, DeclarativeMeta)):
# unless we're expanding this field, stop here
if field not in fields_to_expand:
# not expanding this field: set it to None and continue
fields[field] = None
continue
fields[field] = val
# a json-encodable dict
return fields
return json.JSONEncoder.default(self, obj)
return AlchemyEncoder
Bây giờ bạn có thể gọi nó với:
print json.dumps(e, cls=new_alchemy_encoder(False, ['parents']), check_circular=False)
Ví dụ, để chỉ mở rộng các trường SQLAlchemy được gọi là 'cha mẹ'.