What's the alternative to back-reference property in NDB?
Asked Answered
A

1

6

I have read this question and the simple and clear answer but it's not useful in my case because the answer don't consider the nested for. please, see the code:

class SuperCat(ndb.Model):

class Category(ndb.Model):
  supercat = ndb.KeyProperty(kind=SuperCat)

class SubCat(ndb.Model):
  category = ndb.KeyProperty(kind=Category)

handler:

Categories = ndb.gql("SELECT * FROM Category WHERE supercat = :1", supercat_key)
self.generate('supercat.html', {'Categories': Categories})

in template, with the old db.Model and the back-reference property this is enough:

{{ for Category in Categories }}
  {{ for SubCat in Category.subcat_set }} # this is the back-reference in action

What is the equally simple alternative to serve such data structure?

Antre answered 20/6, 2012 at 15:24 Comment(1)
seems that Structured Properties is a good start point..Antre
I
11

Let's look at this systematically. First, the db->ndb translation guide tells us that the query returning SubCategory instances for a given Category instance is as follows:

  subcats_query = SubCategory.query(SubCategory.category == cat.key)

(Note that I use lowercase names for instances/entities and CapWords for classes/models. So cat is a Category entity.)

So in Python, we would write your double loop as follows:

  for cat in categories:
    for subcat in SubCat.query(SubCat.category == cat.key):
      ...blah...

In order to turn this into something that's easily accessible from the template, let's define a new method on the Category class:

  class Category(ndb.Model):

    supercat = ndb.KeyProperty(kind=SuperCat)

    def subcat_set(self):
      return SubCat.query(SubCat.category == self.key)

Note that this is a method; in Python, you have to call it:

  for cat in categories:
    for subcat in cat.subcat_set():
      ...blah...

But in a template you can (must) leave out the () call syntax, so you get what you want:

  {{ for cat in categories }}
    {{ for subcat in cat.subcat_set }}
      ...blah...

Give it a try!

Iminourea answered 23/6, 2012 at 4:33 Comment(2)
works! but only with () in template. without () i get a TypeError: 'instancemethod' object is not iterable.Antre
What template system are you using? I thought Django auto-calls callables. But maybe Jinja2 doesn't? If you don't like the (), you can decorate the method with @property (lowercase 'p', a Python built-in).Iminourea

© 2022 - 2024 — McMap. All rights reserved.