添加到memcache时的PicklingError

时间:2012-11-23 13:22:21

标签: python google-app-engine

我正试图在App Engine上第一次使用memcache并且遇到了“PicklingError”。

我尝试过memcache的第一个地方是在网站的主页上,我从数据存储中获取内容:

def get(self):
    content = memcache.get('home:content')
    if content is None:
        all_content = Content.all()
        all_content.order("-views")
        all_content.filter('published =', True)
        content = all_content.run(batch_size=5, limit=5)
        memcache.add(key='home:content', value=content, time=120)

(请注意,如果没有尝试将内容Query对象放入memcache,这样可以正常工作。这是它在最后一行(memcache.add ...)上发生的错误:

PicklingError: Pickling of datastore_query.Batcher is unsupported.

以下是内容的模型:

class Content(db.Model):
    category = db.StringProperty(required = True)
    content_type = db.StringProperty(required = True)
    published = db.BooleanProperty(default = False)
    title = db.StringProperty(required = True)
    abstract = db.TextProperty(required = True)
    summary = db.TextProperty(required = True)
    URL = db.LinkProperty(required = True)
    youtube_id = db.StringProperty(required = False)
    thumbnail = db.LinkProperty(required = True)
    post_author = db.StringProperty(required = True)
    author_url = db.LinkProperty(required = False)
    date_post = db.DateTimeProperty(required = True, auto_now_add = True)
    date_source = db.DateTimeProperty(required = False)    
    # todo: split out to use decent shardedcounter approach
    views = db.IntegerProperty(default = 0)
    up_votes = db.IntegerProperty(default = 0)
    down_votes = db.IntegerProperty(default = 0)    
    def votes(self):
        return self.up_votes - self.down_votes

我正在努力弄清楚PicklingError是什么以及如何将Query对象存储到memcache中。我的问题: 我究竟做错了什么? 这是因为我正在尝试缓存迭代器吗? 缓存Query对象是否有任何值,并且每次加载页面都需要调用.run()?

1 个答案:

答案 0 :(得分:2)

查看memcache的{​​{3}}。

简而言之,这是因为您的值必须以简单的方式序列化,因此默认情况下pickle(实际上cPickle)用于序列化您传入的对象。

调用add时,会调用_set_with_policy,然后调用_set_multi_async_with_policy。在_set_multi_async_with_policy中,键值对传递为mapping并且为source

for key, value in mapping.iteritems():
  server_key = _key_string(key, key_prefix, user_key)
  stored_value, flags = _validate_encode_value(value, self._do_pickle)

在辅助方法_validate_encode_value中,如果传入的对象不是可识别的对象,例如intboolstr,方法serialized in a loop对象:

else:
  stored_value = do_pickle(value)
  flags |= TYPE_PICKLED

更新:当您调用run时,会返回attempts to pickle,其中包含查询中包含的某些对象。如果您只想挑选结果,可以通过

将此迭代器强制转换为列表
content = list(all_content.run(batch_size=5, limit=5))

如果您想要保留其他部分,您需要某种自定义选择器。作为Batcher中的iterator object

  def __getstate__(self):
    raise pickle.PicklingError(
        'Pickling of datastore_query.Batch is unsupported.')

datastore_query中定义的大多数类 - 定义大多数查询行为的相同类 - 强烈反对在调用PicklingError时抛出__getstate__来进行酸洗。如果您从未玩过它,__getstate____setstate__是自定义方法,可以帮助挑选和取消对象。