Tengo una tabla llamada Mensaje que tiene un contenido de columna de tipo JSON
La definición de mi modelo solicitada es la siguiente
class Message(db.Model): ... content = db.Column(JSON) ...ahora realizo la coincidencia de texto para una búsqueda simple con la siguiente consulta
Message.query.filter(Message.content['summary'].cast(Unicode).match(term))funciona bien, hasta que el término tiene un carácter utf-8, como diéresis alemana o acentos franceses.
¿Cuál sería la solución aquí?
también tenga en cuenta que estoy usando Python 3
El problema radica en la cast(Unicode) de una columna json de Postgresql. Simplemente lanza el json al tipo de texto subyacente de Unicode de SQLAlchemy, en el caso de Postgresql VARCHAR . En otras palabras, produce una representación de cadena de JSON en lugar de extraer el contenido del texto. Si su entrada contenía puntos de código Unicode escapados, se muestran como en este caso. Dado un modelo de Test simple con una columna de datos json :
In [7]: t = Test(data={'summary': 'Tämä on summary.'}) In [8]: session.add(t) In [9]: session.commit() In [11]: session.query(Test.data['summary'].cast(Unicode)).scalar() Out[11]: '"T\\u00e4m\\u00e4 on summary."' Debería ser evidente por qué fallará una coincidencia con caracteres Unicode sin escape. La forma correcta de extraer el contenido del texto, sin escape de unicode escapado, es usar astext , que usa el operador ->> en Postgresql:
In [13]: session.query(Test.data['summary'].astext).scalar() Out[13]: 'Tämä on summary.'Citando las funciones JSON y la documentación de los operadores:
Nota: Muchas de estas funciones y operadores convertirán los escapes Unicode en cadenas JSON al carácter individual apropiado. Esto no es un problema si la entrada es de tipo jsonb, porque la conversión ya se realizó; pero para la entrada json, esto puede generar un error, como se indica en la Sección 8.14 .
Entonces en tu caso:
Message.query.\ filter(Message.content['summary'].astext.match(term)) Tenga en cuenta que esto solo se aplica al tipo json , no a jsonb , porque el tipo json no convierte los escapes Unicode en la entrada. jsonb , por otro lado, convierte todos los escapes Unicode en caracteres ASCII o UTF-8 equivalentes para el almacenamiento . Si nuestro modelo Test contuviera una segunda columna data2 jsonb , con exactamente la misma entrada, el resultado sería:
In [11]: session.query(Test.data['summary'].cast(Unicode), ...: Test.data2['summary'].cast(Unicode)).first() Out[11]: ('"T\\u00e4m\\u00e4 on summary."', '"Tämä on summary"') Aún así, debe usar astext , si desea texto en lugar de una representación de cadena de JSON.