【问题标题】:GAE: how to add new data in a memcache varGAE:如何在 memcache var 中添加新数据
【发布时间】:2013-05-22 09:31:03
【问题描述】:

我现在被屏蔽了。

问题是这样的:我有一个存储在内存缓存中的书籍列表的“视图”。如果我添加一本新书,我想将新书添加到存储书籍列表的 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' has no attribute 'title'”,当试图表示这一行时:

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

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

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

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

【问题讨论】:

  • 与答案无关..但在Python中不要使用CamelCase作为函数但lower_case_underscores..;)
  • 感谢@Lipis 的提示。我觉得小写风格很丑,但如果是约定,我会改变它。
  • it_is_much_easier_to_read_if_think_about_it compareToTheCamelCaseThingThatIsUnreadable :) python.org/dev/peps/pep-0008/#function-names
  • 他,他,我同时在读python.org/dev/peps/pep-0008/#descriptive-naming-styles。但是……对我来说,阅读 lower_case_names 和 CamelCaseNames 是一样的。我已经习惯了 CamelCase,而且我很容易阅读。

标签: python google-app-engine memcached


【解决方案1】:

在设置内存缓存值时,您正在做两件不同的事情。在getAll 中,在缓存未命中时,您会执行memcache.set(key, books),其中books 是Book 实例的列表。但是在addMemcache(由save) 调用)中,您插入了一个列表列表,其中内部列表是书名和作者。所以正如您所指出的,当您获得值时从缓存中,它们是实例和列表的混合体。

似乎保存中的行应该是:

cls.addMemcache(book)

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

(另请注意,我可能会将addMemcache 设为普通实例方法而不是类方法,这会将self 添加到内存缓存列表中。保存时最好实例化cls 而不是显式调用Book,以防你曾经继承过。)

【讨论】:

  • 完美的@DanielRoseman,就像一个魅力。我通常会忘记 Python 的强大功能并开始做复杂的事情,而 Python 一切都变得更容易了!!也谢谢你的笔记,非常聪明。有什么更新建议吗?也许只是删除并再次添加它?对于删除,我假设我需要搜索标题并将其删除。
  • 我找到了正确的解决方案,谢谢。将在几个小时内发布(我无法自动回复自己,直到 8 小时,没有足够的声誉)。
【解决方案2】:

在@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()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-06
    • 2012-07-10
    • 2017-09-14
    相关资源
    最近更新 更多