Каков хороший способ получить ссылочный объект для каждого элемента списка из хранилища данных в Django на Google App Engine

Я использую Django-nonrel в Google App Engine и имею следующие модели (они упрощены).

class Author(models.Model):
    name = models.CharField()

class Book(models.Model):
    author = models.ForeignKey(Author)
    title = models.CharField()

Итак, если я запрошу вот так,

books = Book.objects.all()

и передайте книги в шаблон и отобразите их, как показано ниже,

<ul>
{% for book in books %}
   <li>{{ book.title }}{{ book.author.name }}</li>
{% endfor %}
</ul>

Я вижу кучу datastore.get в AppStats из-за book.author.name. Я думал, что должен использовать select_related() при запросе книг, но, очевидно, django nonrel не поддерживает, поскольку в Google App Engine нет JOIN.

Может ли кто-нибудь научить меня, как мне действовать в таком сценарии? Должен ли я рассмотреть вопрос о денормализации моих моделей? Буду признателен, если расскажете, как вы с ним работаете.

Спасибо, Ю


person Yoo Matsuo    schedule 24.05.2011    source источник


Ответы (2)


Это происходит из-за количества вызовов RPC, происходящих в ссылочном свойстве. Вы должны выполнить предварительную выборку свойства ссылки, чтобы преодолеть накладные расходы RPC. Я не уверен, как сделать предварительную выборку ссылочного свойства в django-nonrel. Взгляните на этот блог Ника. Это объясняет, как преодолеть накладные расходы RPC ссылочного свойства в appengine. В django-nonrel вы должны понять это сами.

person Abdul Kader    schedule 24.05.2011
comment
Спасибо Абдул. Its very helpful to know how google app engine app should handle this case. Ill попытается выяснить, как добиться этого на Django nonrel позже. - person Yoo Matsuo; 24.05.2011

Я изо всех сил пытался найти способ get_value_from_datastore в Django-Nonrel, как сказал Абдул, в течение нескольких дней. Но не повезло. Так что я, наконец, спросил @wkornewald в Твиттере, тогда он указал мне использовать model.<foreignkey>_id.

Теперь я перенес решение Ника на Django-nonrel. Я относительно новичок в Python, так что это может быть не очень хорошее кодирование, но работает так, как я ожидаю.

def prefetch_refprop(entities, prop_id, prop, filter):
    ref_ids = [getattr(x, prop_id) for x in entities]
    ref_entities = dict((x.id, x) for x in filter(id__in=ref_ids))
    for entity, ref_id in zip(entities, ref_ids):
        setattr(entity, prop, ref_entities[ref_id])
    return entities   

#Usage
books = Book.objects.filter(...)
prefetch_refprop(books, 'author_id', 'author', getattr(Author.objects, 'filter'))

Спасибо всем.
Ю

person Yoo Matsuo    schedule 30.05.2011