2012-05-15 17 views
5

Estoy usando mongodb y redis, redis es mi caché.Guardar unicode en redis pero obtener error

estoy almacenamiento en caché de objetos mongodb con Redis-py:

obj in mongodb: {u'name': u'match', u'section_title': u'\u6d3b\u52a8', u'title': 
u'\u6bd4\u8d5b', u'section_id': 1, u'_id': ObjectId('4fb1ed859b10ed2041000001'), u'id': 1} 

el obj obtienen de Redis con hgetall (clave, obj) es:

{'name': 'match', 'title': '\xe6\xaf\x94\xe8\xb5\x9b', 'section_title': 
'\xe6\xb4\xbb\xe5\x8a\xa8', 'section_id': '1', '_id': '4fb1ed859b10ed2041000001', 'id': '1'} 

Como se puede ver, obj descabellada de caché es str en lugar de unicode, entonces en mi aplicación, hay un error como: códec 'ascii' no puede decodificar byte 0xe6 en posición 12: ordinal no en rango (128)

¿Alguien puede dar algunas sugerencias? gracias

+1

¿Y cómo se guardan los objetos mongodb en redis? – Denis

Respuesta

7

Actualización, para configuración global, marque jmoz's answer.

Si está utilizando terceros lib como django-redis, es posible que necesite especificar una personalizada ConnectionFactory:

class DecodeConnectionFactory(redis_cache.pool.ConnectionFactory): 
    def get_connection(self, params): 
     params['decode_responses'] = True 
     return super(DecodeConnectionFactory, self).get_connection(self, params) 

Suponiendo que está usando Redis-py, es mejor que a pase str en lugar de unicode a Redis, o bien Redis will encode it automatically para los comandos *set, normalmente in UTF-8. Para los comandos *get, Redis no tiene idea acerca del tipo formal de un valor y tiene que devolver el valor directamente en str.

Por lo tanto, como dijo Denis, la forma en que se almacena el objeto a Redis es fundamental. Debe transformar el valor en str para que la capa Redis sea transparente para usted.

También, en lugar de utilizar set the default encoding to UTF-8ascii

+0

¿Por qué lo codifican automáticamente pero luego solo te dejan una cadena en get? – jmoz

+0

@jmoz No estoy seguro, tal vez el autor sabe el motivo = p.Pero a diferencia del adaptador como psycopg2, normalmente el cliente redis-py no almacena el tipo de datos original con los datos. Por lo tanto, no hay forma de saber exactamente qué tipo de datos (cadena) es originalmente y cómo decodificarlos. Tal vez insistir en 'str' en lugar de aceptar otros tipos de valor y luego convertirlos a' str' implícitamente, es mejor, pero quién sabe. – okm

+1

@okm El otro día encontré algo sobre esto, verifique mi respuesta. – jmoz

6

para cada cadena, puede usar la función decode para transformarla en utf-8, p. para el valor si el campo de título en el código:

In [7]: a='\xe6\xaf\x94\xe8\xb5\x9b' 

In [8]: a.decode('utf8') 
Out[8]: u'\u6bd4\u8d5b' 
+0

Hombre, creo que es querer hacer caché, no para decodificar-codificar la diversión, sino para aumentar el sistema. – Denis

3

Te sugiero siempre codificar en UTF-8 antes de escribir en MongoDB o Redis (o cualquier sistema externo). Y que decodifique ('utf-8') cuando obtenga resultados, para que siempre trabaje con Unicode en Python.

25

creo que he descubierto el problema. Después de leer esto, tuve que decodificar explícitamente de redis, que es un dolor, pero funciona.

Me tropecé con una publicación de blog en la que la salida del autor era de cadenas unicode, que obviamente era diferente de la mía.

Al mirar en el StrictRedis.__init__ hay un parámetro decode_responses que por defecto es False. https://github.com/andymccurdy/redis-py/blob/273a47e299a499ed0053b8b90966dc2124504983/redis/client.py#L446

Pase en decode_responses=True en la construcción y para mí este FIXES THE OP'S ISSUE.

+0

Gracias, lo intentaré más tarde. Esta quizás sea la mejor solución ya que no voy a estropear mi código. – goofansu

+0

Esto es asombroso. Gracias. –

+1

Esta debería ser la respuesta aceptada – raben

Cuestiones relacionadas