GAE:如何在memcache var中添加新数据

时间:2013-05-22 09:31:03

标签: python google-app-engine memcached

我现在被封锁了。

问题在于:我对存储在memcache中的书籍列表进行了“查看”。如果我添加一本新书,我想将新书添加到存储书籍列表的memcache变量中。更新和删除相同。

您可以说:“您可以刷新密钥并再次收集所有数据”。但由于最终的一致性,当我添加并立即查询新数据时,新数据仍然不存在。

你可以说:“使用祖先来避免最终的一致性”。这些书是根实体,为了表现,在这个级别使用祖先不是一个好主意。

因此,我们的想法是尽可能少地从数据存储区读取,并使memcache同步。

现在我的代码不起作用:

class Book(ndb.Model):
    """ A Book """
    title = ndb.StringProperty(required=True)
    author = ndb.StringProperty(required=True)

    @classmethod
    def getAll(cls):
        key = 'books'
        books = memcache.get(key)
        if books is None:
            books = list(Book.query().order(Book.title).fetch(100))
            if not memcache.set(key, books):
                logging.error('Memcache set failed for key %s.', key)
        else:
            logging.info('Memcache hit for key %s.', key)
        return books

    @classmethod
    def addMemcache(cls, newdata):
        mylist = memcache.get('books')
        if mylist:
            mylist.insert(0, newdata)
            if not memcache.set('books', mylist):
                logging.error('Memcache set failed for key books.')

    # This saves the data comming from the form
    @classmethod
    def save(cls, **kwargs):
        book = Book(title=kwargs['title'],
                    author=kwargs['author']
               )
        # Save
        book.put()
        # Add to memcache for this key
        logging.info('Adding to Memcache for key books.')
        cls.addMemcache([book.title, book.author])
        return book

现在我只是插入列表的开头。 我的代码的问题是当我添加到memcache时,我缺少某种属性,因为jinja模板说“UndefinedError:'list object'没有属性'title'”,当试图表示这一行: / p>

<td>{{ line.title[:40]|escape }}</td>

这是显而易见的,因为它是一个列表,而不是具有属性的对象。但是为什么它在我在函数getAll()中转换列表中的对象时起作用,使books = list(the_query)?

我的其他问题将是如何修改一个特定的书(在这种情况下,我可以刷新de memcache并再次阅读,因为我认为没有最终的一致性问题)以及如何删除(如何识别一个独特的元素如果2本书有相同的名称,请列出。)

有什么建议吗?或者我必须将解决方案改为让memcache同步的问题吗?

2 个答案:

答案 0 :(得分:3)

设置memcache值时,您正在做两件事。在getAll中,在缓存未命中时,您执行memcache.set(key, books),其中books是Book实例的列表。但是在addMemcache中(由save)调用,您插入一个列表列表,其中内部列表是该书的标题和作者。正如您所指出的那样,你从缓存中获取值,它们是实例和列表的混合。

似乎保存中的行应该是:

cls.addMemcache(book)

以便您始终将Book实例设置为缓存。

(另请注意,我可能会使addMemcache成为普通的实例方法,而不是类方法,它会将self添加到内存缓存列表。而在保存时,最好实例化{{1}而不是显式调用cls,以防你曾经是子类。)

答案 1 :(得分:1)

在@DanielRoseman的帮助下,我得到了问题的最终解决方案。

我只想留下其他感兴趣的“堆叠器”的完整解决方案。它包括对memcache的添加,编辑和删除元素,这些元素现在正在运行。

# These classes define the data objects to store in AppEngine's data store.
class Book(ndb.Model):
    """ A Book """
    title = ndb.StringProperty(required=True)
    author = ndb.StringProperty(required=True)
    deleted = ndb.BooleanProperty(default=False)

    MEMCACHE_TIMEOUT = 0

    # Key to use in memcache for the list of all books
    @staticmethod
    def book_memkey(key='book_list'):
        return str(key)

    # Search all
    @classmethod
    def get_all(cls):
        key = cls.book_memkey()
        books = memcache.get(key)
        if books is None:
            books = list(Book.query().order(Book.title).fetch(100))
            if not memcache.set(key, books, cls.MEMCACHE_TIMEOUT):
                logging.error('Memcache set failed for key %s.', key)
        else:
            logging.info('Memcache hit for key %s.', key)
        return books

    # Save a Book and return it
    @classmethod
    def save(cls, **kwargs):
        book = cls(title=kwargs['title'],
                   author=kwargs['author']
                  )
        book.put()
        # Modify memcache for this key
        book.add_to_memcache()
        return book

    # ------------------------
    # Methods for the instance
    # ------------------------

    # Add a new element to memcache
    def add_to_memcache(self):
        data = memcache.get(self.book_memkey())
        if data:
            logging.info('Adding to Memcache for key %s.', self.book_memkey())
            data.insert(0, self)
            if not memcache.set(self.book_memkey(), data, self.MEMCACHE_TIMEOUT):
                logging.error('Memcache set failed for key %s.', self.book_memkey())

    # Remove an element from memcache
    def del_from_memcache(self):
        data = memcache.get(self.book_memkey())
        if data:
            logging.info('Removing from Memcache for key %s.', self.book_memkey())
            try:
                # Search the object in the list
                element = filter(lambda idx: idx.key == self.key, data)[0]
            except IndexError:
                pass
            else:
                logging.info('Removing element %s.', element)
                data.remove(element)
                if not memcache.set(self.book_memkey(), data, self.MEMCACHE_TIMEOUT):
                    logging.error('Memcache set failed for key %s.', self.book_memkey())

    # Update an element on memcache
    def update_memcache(self):
        data = memcache.get(self.book_memkey())
        if data:
            logging.info('Updating Memcache for key %s.', self.book_memkey())
            try:
                # Search the object in the list
                element = filter(lambda idx: idx.key == self.key, data)[0]
            except IndexError:
                pass
            else:
                logging.info('Updating element %s.', element)
                data[data.index(element)] = self
                if not memcache.set(self.book_memkey(), data, self.MEMCACHE_TIMEOUT):
                    logging.error('Memcache set failed for key %s.', self.book_memkey())

    # Update a chapter
    def update(self, **kwargs):
        if 'title' in kwargs:
            self.title = kwargs['title']
        if 'author' in kwargs:
            self.author = kwargs['author']
        # Save
        self.put()
        self.update_memcache()

    # Delete de book (mark as deleted). Optionally you can assign Value=False to undelete
    def virtual_delete(self, value=True):
        self.deleted = value
        if value:
            self.del_from_memcache()
        else:
            self.add_to_memcache()
        self.put()