#google-app-engine #unicode #utf-8 #google-cloud-datastore
#google-app-engine #unicode #utf-8 #google-облачное хранилище данных
Вопрос:
Используя Google App Engine (python SDK), я создал пользовательский JsonProperty() в качестве подкласса db.TextProperty(). Моя цель — сохранить python dict «на лету» в формате JSON и легко извлекать его. Я следовал различным примерам, найденным через Google, и настройка пользовательского класса свойств и методов довольно проста.
Однако некоторые из моих значений dict (строк) закодированы в utf-8. При сохранении модели в хранилище данных я получаю страшную ошибку Unicode (для текстового свойства хранилища данных кодировкой по умолчанию является ASCII). Создание подкласса db.BlobProperty не решило проблему.
В принципе, мой код выполняет следующее: сохраняет объекты ресурсов в хранилище данных (с URL в качестве свойства StringProperty и полезной нагрузкой POST / GET, хранящейся в dict в виде свойства JsonProperty), извлекает их позже (код не включен). Я предпочитаю не использовать pickle для хранения полезных нагрузок, потому что я фанат JSON и не использую хранение объектов.
Пользовательское свойство JsonProperty :
class JSONProperty(db.TextProperty):
def get_value_for_datastore(self, model_instance):
value = super(JSONProperty, self).get_value_for_datastore(model_instance)
return json.dumps(value)
def make_value_from_datastore(self, value):
if value is None:
return {}
if isinstance(value, basestring):
return json.loads(value)
return value
Помещение модели в хранилище данных :
res = Resource()
res.init_payloads()
res.url = "http://www.somesite.com/someform/"
res.param = { 'name': "SomeField", 'default': u"éàôfoobarç" }
res.put()
Это вызовет ошибку UnicodeDecodeError, связанную с кодировкой ASCII. Возможно, стоит отметить, что я получаю эту ошибку (каждый раз) только на производственном сервере. Я использую python 2.5.2 для разработчиков.
Обратная трассировка (последний вызов last): File «/base/data/home/apps/delpythian/1.350065314722833389/core/handlers/ResetHandler.py «, строка 68, в _res_one возвращает res_one.put() Файл «/base/python_runtime/python_lib/versions/1/google / appengine/ext/db/init.py», строка 984, в файле put return datastore.Put(self._entity, config=config) «/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py «, строка 455, в Put возвращает _GetConnection().async_put(config, entities, extra_hook).get_result() Файл «/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_rpc.py «, строка 1219, в async_put для pbs в pbsgen: File «/base/python_runtime/python_lib/versions/1/google/appengine/datastore/datastore_rpc.py «, строка 1070, в файле __generate_pb_lists pb = value_to_pb(значение) «/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py «, строка 239, в entity_to_pb возвращает объект._ToPb() Файл «/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore.py «, строка 841, в _ToPb properties = datastore_types. datastore_types.ToPropertyPb(имя, значения) Файл «/base/python_runtime/python_lib/versions/1/google/appengine/api/datastore_types.py «, строка 1672, в ToPropertyPb pbvalue = pack_prop(name, v, pb.mutable_value()) Файл «/base/python_runtime/python_lib/versions/1/google/ appengine/api/datastore_types.py», строка 1485, в PackString pbvalue.set_stringvalue(юникод(значение).encode(‘utf-8’)) Ошибка UnicodeDecodeError: кодек ‘ascii’ не может декодировать байт 0xc3 в позиции 32: порядковый номер не входит в диапазон (128)
Мой вопрос заключается в следующем: есть ли способ подклассировать класс db.TextProperty() и установить / применить пользовательскую кодировку? Или я делаю что-то не так? Я стараюсь избегать использования str () и следовать правилу «Декодировать рано, везде юникод, кодировать поздно».
Обновление: добавлен код и трассировка стека.
Комментарии:
1. Пожалуйста, добавьте примеры кода и трассировку стека. В частности, я хотел бы подтвердить, что ошибка UnicodeError возникает при попытке сохранить TextProperty, а не ранее, когда вы пытаетесь сериализовать свой словарь Python в JSON.
2. Обновленный вопрос, добавлен код и трассировка стека.
Ответ №1:
Вот минимальный пример перемещения строки unicode из словаря в сериализованную строку JSON в TextProperty:
class Thing(db.Model):
json = db.TextProperty()
class MainHandler(webapp.RequestHandler):
def get(self):
data = {'word': u"rxe9sumxe9"}
json = simplejson.dumps(data, ensure_ascii=False)
Thing(json=json).put()
У меня это работает как в dev, так и в prod.
Комментарии:
1. Здравствуйте и спасибо, я не думал о том, чтобы посмотреть на метод dumps (). Тем не менее, я все еще получаю ту же трассировку стека в prod. Отлично работает на dev. Это сбивает с толку!
Ответ №2:
Смотрим на строку: PackString pbvalue.set_stringvalue(юникод(значение).encode(‘utf-8’)) Ошибка UnicodeDecodeError: ‘ascii’
похоже, что appengine ожидает, что все строковые значения будут в юникоде. вызов unicode (значение) не указывает кодировку, поэтому, вероятно, по умолчанию будет ascii, если значение уже не является unicode, например:
>>> u = u"ąęćźż"
>>> s = u.encode('utf-8')
>>> unicode(u) # fine
>>> unicode(s, 'utf-8') # fine
>>> unicode(s) # blows up (try's ascii) (on my interpreter)
json.dumps будет кодировать строку utf-8 (по умолчанию), и именно поэтому unicode не может ее обработать.
попробуйте это:
>>> return unicode(json.dumps(...), 'utf-8')
и все должно быть в порядке.
Что касается того, почему appengine взрывается, а ваш интерпретатор в порядке, я предполагаю, что это какие-то локальные настройки, docstring для unicode говорит, что по умолчанию используется текущая кодировка по умолчанию, которая, по-видимому, является utf-8 для вас и ascii для gae.