Düz bir uygulama
Bunun gibi bir şey kullanabilirsiniz:
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)
ve daha sonra kullanarak JSON'a dönüştürün:
c = YourAlchemyClass()
print json.dumps(c, cls=AlchemyEncoder)
Kodlanamayan alanları yoksayar (onları 'Yok' olarak ayarlayın).
İlişkileri otomatik olarak genişletmez (çünkü bu, kendi referanslarına yol açabilir ve sonsuza dek döngüye girebilir).
Yinelemeli, dairesel olmayan bir uygulama
Ancak, sonsuza kadar döngü yapmayı tercih ederseniz, şunları kullanabilirsiniz:
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
Ve sonra nesneleri kullanarak kodlayın:
print json.dumps(e, cls=new_alchemy_encoder(), check_circular=False)
Bu, tüm çocukları, tüm çocuklarını ve tüm çocuklarını kodlar ... Temelde, tüm veritabanınızı potansiyel olarak kodlar. Daha önce kodlanmış bir şeye ulaştığında, onu 'Hiçbiri' olarak kodlayacaktır.
Özyinelemeli, muhtemelen dairesel, seçici bir uygulama
Muhtemelen daha iyi olan başka bir alternatif, genişletmek istediğiniz alanları belirleyebilmektir:
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
Şimdi şununla arayabilirsiniz:
print json.dumps(e, cls=new_alchemy_encoder(False, ['parents']), check_circular=False)
Örneğin, yalnızca 'ebeveynler' olarak adlandırılan SQLAlchemy alanlarını genişletmek için.