Storing a lambda function in the Google App Engine Datastore (python 2.7)

199 Views Asked by At

I am creating a bunch of Foo objects in GAE.

I want each Foo to have a function called fooify(). Calling fooify(object) should return object, but transformed in some way.

For example, fooify([2,3]) might return:

  • [1,2] (fooify = lambda x: [n-1 for n in x])
  • [2,3] (fooify = lambda x: x)
  • [2,4] (fooify = lambda x: [x[0],x[1]+1])

I want to be able to define what fooify does when I create my objects, preferably with something like:

foo1=Foo()
foo1.fooify=lambda x: [n^2 for n in x]
foo1.put()

The Foo class looks like:

from google.appengine.ext import ndb
class Foo(ndb.Model):
    name=ndb.StringProperty(default="generic foo", indexed=True)
    fooify=ndb.SOMETHINGProperty(indexed=False)    # This contains the function

I know this isn't what the datastore is made for, but would still like to do it. Currently the only option I can see is something like the following:

class Foo(ndb.Model):
    name=ndb.StringProperty(default="generic foo", indexed=True)
    fooify_str=ndb.StringProperty(indexed=False)    # Contains something like "lambda x: [n+3 for n in x]"

    def fooify(self,obj):
        func = eval(self.fooify_str)
        return func(obj)

Which uses eval() to create the main part of the fooify function. I don't want to use eval() because it seems sort of hack-ish, and it also means that I have to write all the fooify_str functions as strings, (annoying - no syntax highlighting, etc.)

Is there another way around this that I'm missing?

1

There are 1 best solutions below

0
On

Using polymodel may suit your needs if your different fooify functions are somewhat organized in a class hierarchy.

You can define your model:

class Foo(polymodel.PolyModel):
  name = ndb.StringProperty()

class MyFirstFoo(Foo):
  def fooify(self, obj):
    ...

class MySecondFoo(Foo):
  def fooify(self, obj):
    ...

ndb will store these all under the Foo kind, so any query over Foo will return all the results (i.e. Foo.query().filter(...). However, it keeps track of the class hierarchy, so when you load the entity it knows it is a MyFirstFoo versus MySecondFoo.