Сейчас я заблокирован.
Проблема заключается в следующем: у меня есть "просмотр" списка книг, хранящихся в 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?
При настройке значений memcache вы выполняете две разные вещи. В getAll
, при пропуске кеша, вы делаете memcache.set(key, books)
где books
- это список экземпляров книги. Но в addMemcache
(addMemcache
save)
вы вставляете список списков, где внутренний список - это заголовок и автор книги. Как вы заметили, когда вы получаете значения из кеша, они представляют собой смесь экземпляров и списков.
Кажется, что строка в save должна быть только:
cls.addMemcache(book)
так что вы последовательно устанавливаете экземпляры Book в кеш.
(Также обратите внимание, что, вероятно, я бы addMemcache
обычный метод экземпляра, а не метод класса, который добавляет self
в список memcache. И в сохранении было бы лучше создать экземпляр cls
а не явно ссылаться на Book
, если вы когда-либо выполняли подкласс.)
С помощью @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()