Estoy almacenando JSON como blob/texto en una columna con MySQL. ¿Hay una forma simple de convertir esto en un dict usando python/SQLAlchemy?SQLAlchemy JSON como blob/texto
Respuesta
Usted puede muy fácilmente create your own type con SQLAlchemy
Para las versiones SQLAlchemy> = 0.7, echa un vistazo a Yogesh's answer continuación
import jsonpickle
import sqlalchemy.types as types
class JsonType(types.MutableType, types.TypeDecorator):
impl = types.Unicode
def process_bind_param(self, value, engine):
return unicode(jsonpickle.encode(value))
def process_result_value(self, value, engine):
if value:
return jsonpickle.decode(value)
else:
# default can also be a list
return {}
Esto se puede utilizar cuando se está definiendo sus tablas (ejemplo usa elixir):
from elixir import *
class MyTable(Entity):
using_options(tablename='my_table')
foo = Field(String, primary_key=True)
content = Field(JsonType())
active = Field(Boolean, default=True)
También puede usar un serializador json diferente para jsonpickle.
¿Qué tal json.loads()?
>>> d= {"foo":1, "bar":[2,3]}
>>> s='{"foo":1, "bar":[2,3]}'
>>> import json
>>> json.loads(s) == d
True
gracias, ¿hay alguna manera de hacerlo automáticamente? similar a un disparador en sqlalchemy. – Timmy
creo que el ejemplo de JSON a partir de los documentos SQLAlchemy es también vale la pena mencionar:
http://www.sqlalchemy.org/docs/core/types.html#marshal-json-strings
Sin embargo, creo que se puede mejorar a ser menos estricta en cuanto a NULL y cadenas vacías:
class JSONEncodedDict(TypeDecorator):
impl = VARCHAR
def process_bind_param(self, value, dialect):
if value is None:
return None
return json.dumps(value, use_decimal=True)
def process_result_value(self, value, dialect):
if not value:
return None
return json.loads(value, use_decimal=True)
Esta respuesta funcionó para mí sin tocar types.py. –
NB: Esto solo funcionará si usted trata el valor como inmutable. Entonces, le asigna al atributo del objeto un 'dict' completo. Si intenta modificar solo los elementos del 'dict', sqlalchemy no registrará los cambios y no se guardarán en color. Ver 'sqlalchemy.ext.mutable.Mutable' sobre cómo cambiar eso. –
Esto es lo que se me ocurrió basado en las dos respuestas anteriores.
import json
class JsonType(types.TypeDecorator):
impl = types.Unicode
def process_bind_param(self, value, dialect):
if value :
return unicode(json.dumps(value))
else:
return {}
def process_result_value(self, value, dialect):
if value:
return json.loads(value)
else:
return {}
Tuve un problema con el guardado que se resolvió utilizando un diccionario mutable. http://docs.sqlalchemy.org/en/rel_0_8/orm/extensions/mutable.html –
sqlalchemy.types.MutableType
se ha desaprobado (v0.7 en adelante), la documentation recommends usando sqlalchemy.ext.mutable
su lugar.
Encontré un Git gist por dbarnett que he probado para mi uso. Hasta ahora ha funcionado bien, tanto para el diccionario como para las listas.
pegar a continuación para la posteridad:
import simplejson
import sqlalchemy
from sqlalchemy import String
from sqlalchemy.ext.mutable import Mutable
class JSONEncodedObj(sqlalchemy.types.TypeDecorator):
"""Represents an immutable structure as a json-encoded string."""
impl = String
def process_bind_param(self, value, dialect):
if value is not None:
value = simplejson.dumps(value)
return value
def process_result_value(self, value, dialect):
if value is not None:
value = simplejson.loads(value)
return value
class MutationObj(Mutable):
@classmethod
def coerce(cls, key, value):
if isinstance(value, dict) and not isinstance(value, MutationDict):
return MutationDict.coerce(key, value)
if isinstance(value, list) and not isinstance(value, MutationList):
return MutationList.coerce(key, value)
return value
@classmethod
def _listen_on_attribute(cls, attribute, coerce, parent_cls):
key = attribute.key
if parent_cls is not attribute.class_:
return
# rely on "propagate" here
parent_cls = attribute.class_
def load(state, *args):
val = state.dict.get(key, None)
if coerce:
val = cls.coerce(key, val)
state.dict[key] = val
if isinstance(val, cls):
val._parents[state.obj()] = key
def set(target, value, oldvalue, initiator):
if not isinstance(value, cls):
value = cls.coerce(key, value)
if isinstance(value, cls):
value._parents[target.obj()] = key
if isinstance(oldvalue, cls):
oldvalue._parents.pop(target.obj(), None)
return value
def pickle(state, state_dict):
val = state.dict.get(key, None)
if isinstance(val, cls):
if 'ext.mutable.values' not in state_dict:
state_dict['ext.mutable.values'] = []
state_dict['ext.mutable.values'].append(val)
def unpickle(state, state_dict):
if 'ext.mutable.values' in state_dict:
for val in state_dict['ext.mutable.values']:
val._parents[state.obj()] = key
sqlalchemy.event.listen(parent_cls, 'load', load, raw=True, propagate=True)
sqlalchemy.event.listen(parent_cls, 'refresh', load, raw=True, propagate=True)
sqlalchemy.event.listen(attribute, 'set', set, raw=True, retval=True, propagate=True)
sqlalchemy.event.listen(parent_cls, 'pickle', pickle, raw=True, propagate=True)
sqlalchemy.event.listen(parent_cls, 'unpickle', unpickle, raw=True, propagate=True)
class MutationDict(MutationObj, dict):
@classmethod
def coerce(cls, key, value):
"""Convert plain dictionary to MutationDict"""
self = MutationDict((k,MutationObj.coerce(key,v)) for (k,v) in value.items())
self._key = key
return self
def __setitem__(self, key, value):
dict.__setitem__(self, key, MutationObj.coerce(self._key, value))
self.changed()
def __delitem__(self, key):
dict.__delitem__(self, key)
self.changed()
class MutationList(MutationObj, list):
@classmethod
def coerce(cls, key, value):
"""Convert plain list to MutationList"""
self = MutationList((MutationObj.coerce(key, v) for v in value))
self._key = key
return self
def __setitem__(self, idx, value):
list.__setitem__(self, idx, MutationObj.coerce(self._key, value))
self.changed()
def __setslice__(self, start, stop, values):
list.__setslice__(self, start, stop, (MutationObj.coerce(self._key, v) for v in values))
self.changed()
def __delitem__(self, idx):
list.__delitem__(self, idx)
self.changed()
def __delslice__(self, start, stop):
list.__delslice__(self, start, stop)
self.changed()
def append(self, value):
list.append(self, MutationObj.coerce(self._key, value))
self.changed()
def insert(self, idx, value):
list.insert(self, idx, MutationObj.coerce(self._key, value))
self.changed()
def extend(self, values):
list.extend(self, (MutationObj.coerce(self._key, v) for v in values))
self.changed()
def pop(self, *args, **kw):
value = list.pop(self, *args, **kw)
self.changed()
return value
def remove(self, value):
list.remove(self, value)
self.changed()
def JSONAlchemy(sqltype):
"""A type to encode/decode JSON on the fly
sqltype is the string type for the underlying DB column.
You can use it like:
Column(JSONAlchemy(Text(600)))
"""
class _JSONEncodedObj(JSONEncodedObj):
impl = sqltype
return MutationObj.as_mutable(_JSONEncodedObj)
Basado en respuesta @snapshoe y para responder a @ comentarios de Timmy:
Puede hacerlo mediante el uso de propiedades. He aquí un ejemplo de una tabla:
class Providers(Base):
__tablename__ = "providers"
id = Column(
Integer,
Sequence('providers_id', optional=True),
primary_key=True
)
name = Column(Unicode(40), index=True)
_config = Column("config", Unicode(2048))
@property
def config(self):
if not self._config:
return {}
return json.loads(self._config)
@config.setter
def config(self, value):
self._config = json.dumps(value)
def set_config(self, field, value):
config = self.config
config[field] = value
self.config = config
def get_config(self):
if not self._config:
return {}
return json.loads(self._config)
def unset_config(self, field):
config = self.get_config()
if field in config:
del config[field]
self.config = config
Ahora usted puede utilizarlo en un objeto Providers()
:
>>> p = Providers()
>>> p.set_config("foo", "bar")
>>> p.get_config()
{"foo": "bar"}
>>> a.config
{u'foo': u'bar'}
Sé que esto es una vieja cuestión tal vez incluso muertos, pero espero que esto podría ayudar a alguien .
No es una receta para esto en el official documentation:
from sqlalchemy.types import TypeDecorator, VARCHAR
import json
class JSONEncodedDict(TypeDecorator):
"""Represents an immutable structure as a json-encoded string.
Usage::
JSONEncodedDict(255)
"""
impl = VARCHAR
def process_bind_param(self, value, dialect):
if value is not None:
value = json.dumps(value)
return value
def process_result_value(self, value, dialect):
if value is not None:
value = json.loads(value)
return value
Como una actualización de las respuestas anteriores, que hemos usado con éxito hasta el momento. A partir de MySQL 5.7 y SQLAlchemy 1.1, puede usar native MySQL JSON data type, que le ofrece un mejor rendimiento y un total de range of operators de forma gratuita.
Le permite crear virtual secondary indexes en elementos JSON también.
Pero, por supuesto, usted se encargará de ejecutar su aplicación en MySQL solo cuando mueva la lógica a la base de datos.
- 1. Seleccionar como en sqlalchemy
- 2. Como utilizar "orden compuesto por" en sqlalchemy
- 3. SqlAlchemy - Filtrado por campo definido como ForeignKey
- 4. WCF de jQuery como JSON
- 5. búsqueda de window.location.search como JSON
- 6. Node.js como un forwarder JSON
- 7. JSON diff de datos JSON grandes, encontrando algunos JSON como un subconjunto de otro JSON
- 8. Utilizando las teclas de JSON como atributos en JSON anidada
- 9. ¿Por qué este JSON vuelve como "primitiva JSON inválida"?
- 10. json_encode matriz PHP escaso como array JSON, no objeto JSON
- 11. Como llegar sqlalchemy longitud de una columna de cadena
- 12. Uso de alias() para 'seleccione como' en SQLAlchemy
- 13. ¿Debo utilizar SQLObject, SQLAlchemy o SQLAlchemy + Elixir?
- 14. Volver JSON usando C# como PHP json_encode
- 15. Jquery - Almacene respuesta jSON Ajax como variable
- 16. Envíe un formulario como JSON (no AJAX)
- 17. Jackson Deserialize variable como JSON cadena
- 18. cómo enviar el formulario como objeto JSON
- 19. Usando el número como "índice" (JSON)
- 20. Enviando respuesta Json como cadena e enteros ...
- 21. ASP MVC Ver contenido como JSON
- 22. json obtener nombres clave como texto?
- 23. ¿Cómo se genera una matriz como JSON?
- 24. SQLAlchemy Herencia
- 25. SQLAlchemy sinónimo columna con diferentes tipos
- 26. SQLAlchemy y valores escalares
- 27. SQLAlchemy ¿ORDEN AL DESCENDER?
- 28. SQLAlchemy y columnas vacías
- 29. Usando O en SQLAlchemy
- 30. SQLAlchemy y Postgresql: to_tsquery()
Esto no funcionó para mí. Dentro de la clase MutableType (objeto): def copy_value genera una excepción. def copy_value (self, value): "" "Unimplemented." "" raise NotImplementedError() –
Cambié la fuente y funcionó, pero no me sentía cómodo con los problemas de mantenimiento que esto causaría. –
Gran respuesta ... También tenga en cuenta que PostgreSQL admite un tipo JSON. Esto parece prometedor: es como su ejemplo, pero usará el tipo JSON de PostgreSQL si está disponible. [sqlalchemy-utils JSONType] (http://sqlalchemy-utils.readthedocs.org/en/latest/_modules/sqlalchemy_utils/types/json.html) – hangtwenty