Question

Here's my data model:

BlogPost(ndb.Model):
    title = ndb.StringProperty()
    body = ndb.TextProperty()
    author_key = ndb.KeyProperty() 

Author(ndb.Model):
    name = ndb.StringProperty()
    fav_colour = ndb.StringProperty()

I am currently on my home page ('/'), and I would like to:

  • query for a list of all BlogPost entities, and
  • query for their respective authors to be displayed alongside a BlogPost entity.

I can query for all BlogPosts simply like this:

class BlogPostHandler(webapp2.RequestHandler): 
    def get(self):
        posts = BlogPost.query().fetch()
        self.render('index.html', posts = posts) #renders in Jinja2 template

The Jinja2 index.html template is this:

{% for p in posts %}
    {{p}}
    {{p's AUTHOR TO BE DISPLAYED HERE. Example: author.name, author.fav_colour}}    
{% endfor %}

So, I would like to know how I can display the Author entity which is associated with each BlogPost entity.

Thank you.

Was it helpful?

Solution

The best way to do this would be to denormalize the data and store a copy of the Author name in the BlogPost:

BlogPost(ndb.Model):
    title = ndb.StringProperty()
    body = ndb.TextProperty()
    author_key = ndb.KeyProperty()
    author_name = ndb.StringProperty(indexed=False)

This way you have the author name with the blogpost. Otherwise, you'd need to fetch the list of blogposts, then for each blogpost, fetch the Author entity to get the name. That would be much slower, and much more expensive.

OTHER TIPS

{{p's AUTHOR TO BE DISPLAYED HERE. Example: p.author.get.name, p.author.get.fav_colour}}    

Just a word of caution, this will do a 2 ndb rpc call each time you do a get for the author and will affect performance.
You can use memcache to store the author entity in memcache or denormalize the author information and store it in the post entity.

Here's a way to query every author:

BlogPost(ndb.Model):
    title = ndb.StringProperty()
    body = ndb.TextProperty()
    author_key = ndb.KeyProperty()

    def get_author_async(self):
        self._author_fetch = author_key.get_async()

    @property
    def author_name(self):
        author = self_author_fetch.get_result()
        return author.name if author else ""


class BlogPostHandler(webapp2.RequestHandler): 
    def get(self):
        posts = BlogPost.query().fetch()
        for post in posts:
            post.get_author_async()
        self.render('index.html', posts = posts) #renders in Jinja2 template

So yes, this is easier up front, but assuming your blog app is like most blogs, where each post is edited a handful of times, and viewed 1000x as many times, this is an expensive way to go.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top