Search code examples
pythongoogle-app-enginereferenceproperty

how do I obtain all the elements of a generator expression I wrote?


I am using google-app-engine webapp, part of the code is :

class Post(db.Model):
    title = db.StringProperty(required=True)
    def categories(self):
        return (x.category for x in self.postcategory_set)

class Category(db.Model):
    name = db.StringProperty()

class PostCategory(db.Model):
    post = db.ReferenceProperty(Post)
    category = db.ReferenceProperty(Category)


class sss(webapp.RequestHandler):
  def get(self):
    obj1 = Post(title='hhaa')
    #obj1.title = 'haha'
    obj1.put()

    obj2 = Category()

    obj2.name='haha-kao'

    obj2.put()
    obj3=PostCategory()
    obj3.post=obj1
    obj3.category=obj2
    obj3.put()
    self.response.out.write(obj1.categories().get().name)

but I get an error:

Traceback (most recent call last):
  File "D:\Program Files\Google\google_appengine\google\appengine\ext\webapp\__init__.py", line 511, in __call__
    handler.get(*groups)
  File "D:\zjm_code\helloworld\a.py", line 131, in get
    self.response.out.write(obj1.categories().get().name)
AttributeError: 'generator' object has no attribute 'get'

so how can I obtain all values of the genexp I wrote?


Solution

  • If you wanted an all method you should return a list comprehension instead of a generator:

    return [x.category for x in self.postcategory_set]
    

    but since postcategory_set is already an iterable (because you iterated it)

    return self.postcategory_set
    

    would be more natural, but that would give the caller a reference to your private, mutable data, except in this case Post.postcategory_set is not really a set type but rather an instance of google.app.engine.ext.db.Query which is indeed iterable but not mutable.

    And you didn't ask, but your model is funny, with the PostCategory table being unnecessary when you could have:

    class Post(db.Model):
        title = db.StringProperty(required=True)
        category = db.ReferenceProperty(Category)
        def categories(self):
            return list(self.postcategory_set)
    

    And drop PostCategory completely.