GAE: как добавить новые данные в memcache var

1

Сейчас я заблокирован.

Проблема заключается в следующем: у меня есть "просмотр" списка книг, хранящихся в 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:" объект списка "не имеет атрибута" title ", когда пытается представить эту строку:

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

Это очевидно, потому что это список, а не объект со свойствами. Но почему это работает, когда я конвертирую объект в список в функции getAll(), делая book = list (the_query)?

Мои другие проблемы будут заключаться в том, как изменить специальную книгу (в этом случае я могу очистить memcache и прочитать снова, потому что я не думаю о возможной проблеме согласованности) и как удалить (как идентифицировать уникальный элемент в списке, если 2 книги имеют одно и то же имя).

Любое предложение? Или я должен изменить свое решение проблемы с синхронизацией memcache?

  • 0
    Не имеет ничего общего с ответом .. но в Python dontUseCamelCase для функции, но lower_case_underscores ..;)
  • 0
    Спасибо за совет, @Lipis. Я нахожу стиль в нижнем регистре некрасивым, но если это соглашение, я его поменяю.
Показать ещё 2 комментария
Теги:
google-app-engine
memcached

2 ответа

3
Лучший ответ

При настройке значений memcache вы выполняете две разные вещи. В getAll, при пропуске кеша, вы делаете memcache.set(key, books) где books - это список экземпляров книги. Но в addMemcache (addMemcache save) вы вставляете список списков, где внутренний список - это заголовок и автор книги. Как вы заметили, когда вы получаете значения из кеша, они представляют собой смесь экземпляров и списков.

Кажется, что строка в save должна быть только:

cls.addMemcache(book)

так что вы последовательно устанавливаете экземпляры Book в кеш.

(Также обратите внимание, что, вероятно, я бы addMemcache обычный метод экземпляра, а не метод класса, который добавляет self в список memcache. И в сохранении было бы лучше создать экземпляр cls а не явно ссылаться на Book, если вы когда-либо выполняли подкласс.)

  • 0
    Идеальный @DanielRoseman, работает как шарм. Я обычно забываю всю мощь Python и начинаю делать сложные вещи, когда с Python все проще! Спасибо также за ваши заметки, это было очень умно. Любое предложение для обновления? Может быть, просто удалить и добавить его снова? Для удаления я предполагаю, что мне нужно найти заголовок и удалить его.
  • 0
    Я получил правильное решение, спасибо. Будет опубликовано через несколько часов (я не могу автоответить себя до 8 часов, не достаточно репутации).
1

С помощью @DanielRoseman я получил окончательное решение проблемы.

Я просто хочу оставить здесь полное решение для других заинтересованных "штабелеров". Он включает в себя элементы добавления, редактирования и удаления memcache, которые теперь работают.

# These classes define the data objects to store in AppEngine 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()

Ещё вопросы

Сообщество Overcoder
Наверх
Меню