Django tiene una buena serialización automática de modelos ORM devueltos de DB a formato JSON.
¿Cómo serializar el resultado de la consulta SQLAlchemy al formato JSON?
Lo intenté jsonpickle.encode
pero codifica el objeto de consulta en sí. Lo intenté json.dumps(items)
pero vuelve
TypeError: <Product('3', 'some name', 'some desc')> is not JSON serializable
¿Es realmente tan difícil serializar objetos SQLAlchemy ORM a JSON / XML? ¿No hay ningún serializador predeterminado para ello? Hoy en día es una tarea muy común serializar los resultados de las consultas ORM.
Lo que necesito es devolver la representación de datos JSON o XML del resultado de la consulta SQLAlchemy.
El resultado de la consulta de objetos SQLAlchemy en formato JSON / XML es necesario para ser utilizado en JavaScript DataGird (JQGrid http://www.trirand.com/blog/ )
fuente
Respuestas:
Una implementación plana
Podrías usar algo como esto:
y luego convertir a JSON usando:
Ignorará los campos que no son codificables (configúrelos en 'Ninguno').
No expande automáticamente las relaciones (ya que esto podría conducir a auto-referencias y bucles para siempre).
Una implementación recursiva, no circular
Sin embargo, si prefieres un bucle para siempre, puedes usar:
Y luego codificar objetos usando:
Esto codificaría a todos los hijos, y a todos sus hijos, y a todos sus hijos ... Básicamente, codifique potencialmente toda su base de datos. Cuando alcanza algo que está codificado anteriormente, lo codificará como 'Ninguno'.
Una implementación recursiva, posiblemente circular, selectiva
Otra alternativa, probablemente mejor, es poder especificar los campos que desea expandir:
Ahora puede llamarlo con:
Para expandir solo los campos de SQLAlchemy llamados 'padres', por ejemplo.
fuente
online_order
yaddress
, ambos con una relación conuser
, peroonline_order
también tiene una relación conaddress
. Si quisiera serializar todo esto, tendría que incluirloaddress
en elfields_to_expand
, pero no quisiera serializar de forma redundanteaddress
debido a su relación con ambosuser
yonline_order
.for field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata']:
para que se leafor field in [x for x in dir(obj) if not x.startswith('_') and x != 'metadata' and not x.startswith('query')]:
. Tenga en cuenta que esta solución le impedirá tener una propiedad / relación con el nombre 'query'Simplemente puede generar su objeto como un diccionario:
Y luego usas
User.as_dict()
para serializar tu objeto.Como se explica en Convertir objeto de fila sqlalchemy a python dict
fuente
JSONEncoder
objeto. Puede subclasificarlo para definir su propio codificador para algún objeto, incluida la fecha y hora. Tenga en cuenta queFlask
, por ejemplo, admite la codificación de fecha y hora en JSON fuera de la caja (con la última versión).return {c.name: unicode(getattr(self, c.name)) for c in self.__table__.columns}
Puede convertir un RowProxy a un dict como este:
Luego, serialice eso a JSON (tendrá que especificar un codificador para cosas como
datetime
valores) No es tan difícil si solo desea un registro (y no una jerarquía completa de registros relacionados).fuente
Recomiendo usar malvavisco . Le permite crear serializadores para representar sus instancias de modelo con soporte para relaciones y objetos anidados.
Aquí hay un ejemplo truncado de sus documentos. Tome el modelo ORM
Author
:Un esquema de malvavisco para esa clase se construye así:
... y usado así:
... produciría una salida como esta:
Eche un vistazo a su ejemplo completo de Flask-SQLAlchemy .
Una biblioteca llamada
marshmallow-sqlalchemy
específicamente integra SQLAlchemy y malvavisco. En esa biblioteca, el esquema para elAuthor
modelo descrito anteriormente se ve así:La integración permite inferir los tipos de campo a partir de los
Column
tipos SQLAlchemy .malvavisco-sqlalchemy aquí.
fuente
Python 3.7+ y Flask 1.1+ pueden usar el paquete de clases de datos incorporado
La
/users/
ruta ahora devolverá una lista de usuarios.Auto-serializar modelos relacionados
La respuesta de
jsonify(account)
sería esta.Sobrescribe el codificador JSON predeterminado
fuente
data = request.json['user']; user = User(**data)
id: int = Column
funcionará, peroid = Column
no lo hará, parece que DEBE declarar la escritura estática para que el json serialice el campo, de lo contrario obtendrá un{}
objeto vacío .pipenv install dataclasses
. Y luego funcionará bien.El paquete Flask-JsonTools tiene una implementación de la clase JsonSerializableBase Base para sus modelos.
Uso:
Ahora el
User
modelo es mágicamente serializable.Si su marco no es Flask, simplemente puede tomar el código
fuente
import flask.ext.whatever
ya que ya no es compatible con Flask 1.0.Por razones de seguridad, nunca debe devolver todos los campos del modelo. Prefiero elegirlos selectivamente.
La codificación json de Flask ahora admite UUID, fecha y hora y relaciones (y agregado
query
yquery_class
para ladb.Model
clase flask_sqlalchemy ). He actualizado el codificador de la siguiente manera:Con esto, opcionalmente puedo agregar una
__json__
propiedad que devuelve la lista de campos que deseo codificar:Agrego @jsonapi a mi vista, devuelvo la lista de resultados y luego mi salida es la siguiente:
fuente
@jsonapi
a@app.route
en views.py etc), pero me encanta la simplicidad de la misma. Creo que es barato Flask agregó datetime pero no date, así que lo agregué yo mismo a json_encoder.py :value=...
^if isinstance(value, date):
^data[field] = datetime.combine(value, time.min).isoformat()
^else:
^try:...
Puede usar la introspección de SqlAlchemy como esta:
Inspírate con una respuesta aquí: Convierte el objeto de fila sqlalchemy a python dict
fuente
Una explicación más detallada. En su modelo, agregue:
El
str()
es para Python 3 por lo que si el uso de pitón 2 usounicode()
. Debería ayudar a deserializar las fechas. Puede eliminarlo si no se trata de eso.Ahora puede consultar la base de datos de esta manera
First()
Es necesario para evitar errores extraños.as_dict()
ahora deserializará el resultado. Después de la deserialización, está listo para convertirse en jsonfuente
No es tan sencillo. Escribí un código para hacer esto. Todavía estoy trabajando en ello, y usa el marco MochiKit. Básicamente traduce objetos compuestos entre Python y Javascript usando un proxy y convertidores JSON registrados.
El lado del navegador para los objetos de la base de datos es db.js. Necesita la fuente básica del proxy Python en proxy.js .
En el lado de Python está el módulo proxy base . Luego, finalmente, el codificador de objetos SqlAlchemy en webserver.py . También depende de los extractores de metadatos que se encuentran en el archivo models.py .
fuente
Si bien la pregunta original se remonta un tiempo, la cantidad de respuestas aquí (y mis propias experiencias) sugieren que es una pregunta no trivial con muchos enfoques diferentes de complejidad variable con diferentes compensaciones.
Por eso construí el SQLAthanor biblioteca que extiende el ORM declarativo de SQLAlchemy con soporte de serialización / configurable que es posible que desee echar un vistazo.
La biblioteca admite:
dict
password
, pero nunca incluir uno saliente )Puede consultar los documentos completos (¡espero!) Aquí: https://sqlathanor.readthedocs.io/en/latest
¡Espero que esto ayude!
fuente
Serialización y deserialización personalizadas.
"from_json" (método de clase) crea un objeto Modelo basado en datos json.
"deserialize" podría llamarse solo en la instancia y fusionar todos los datos de json en la instancia de Model.
"serializar" - serialización recursiva
La propiedad __write_only__ es necesaria para definir propiedades de solo escritura ("password_hash", por ejemplo).
fuente
Aquí hay una solución que le permite seleccionar las relaciones que desea incluir en su salida tan profundo como le gustaría ir. NOTA: Esta es una reescritura completa tomando un dict / str como un argumento en lugar de una lista. arregla algunas cosas ...
así que para un ejemplo usando persona / familia / hogares / habitaciones ... convirtiéndolo en json todo lo que necesitas es
fuente
Pensé que jugaría un pequeño código de golf con este.
FYI: estoy usando automap_base ya que tenemos un esquema diseñado por separado de acuerdo con los requisitos comerciales. Acabo de comenzar a usar SQLAlchemy hoy, pero la documentación indica que automap_base es una extensión de declarative_base que parece ser el paradigma típico en SQLAlchemy ORM, así que creo que esto debería funcionar.
No es elegante seguir las claves foráneas según la solución de Tjorriemorrie , sino que simplemente hace coincidir las columnas con los valores y maneja los tipos de Python mediante str (): los valores de las columnas. Nuestros valores consisten en Python datetime.time y decimal. Resultados de tipo de clase decimal para que haga el trabajo.
¡Espero que esto ayude a los transeúntes!
fuente
Sé que esta es una publicación bastante antigua. Tomé la solución dada por @SashaB y modifiqué según mi necesidad.
Le agregué las siguientes cosas:
Mi código es el siguiente:
Espero que ayude a alguien!
fuente
Use el serializador incorporado en SQLAlchemy:
Si está transfiriendo el objeto entre sesiones, recuerde separar el objeto de la sesión actual usando
session.expunge(obj)
. Para adjuntarlo nuevamente, solo hazlosession.add(obj)
.fuente
El siguiente código serializará el resultado de sqlalchemy a json.
Llamando diversión
fuente
El AlchemyEncoder es maravilloso, pero a veces falla con los valores decimales. Aquí hay un codificador mejorado que resuelve el problema decimal:
fuente
Cuando se usa sqlalchemy para conectarse a un db I, esta es una solución simple que es altamente configurable. Usa pandas.
fuente
fuente
Bajo Flask, esto funciona y maneja campos de datos de tiempo, transformando un campo de tipo
'time': datetime.datetime(2018, 3, 22, 15, 40)
en"time": "2018-03-22 15:40:00"
:fuente
Los choques de serializador integrados con utf-8 no pueden decodificar el byte de inicio no válido para algunas entradas. En cambio, fui con:
fuente
Tal vez puedas usar una clase como esta
Con eso todos los objetos tienen el
to_dict
métodofuente
Mientras usaba algunos objetos sql sin procesar y no definidos,
cursor.description
parecía que usaba para obtener lo que estaba buscando:fuente
Mi opinión utilizando diccionarios (¿demasiados?):
Se ejecuta con flask (incluido jsonify) y flask_sqlalchemy para imprimir salidas como JSON.
Llame a la función con jsonify (serialize ()).
Funciona con todas las consultas SQLAlchemy que he probado hasta ahora (ejecutando SQLite3)
fuente