自定义属性的ListProperty
有没有一种优雅的方式来使用 ListProperty
来存储一个子类的 db.Property
类型呢?
举个例子,FuzzyDateProperty
这个东西来自于 这个例子,它使用 get_value_for_datastore()
和 make_value_from_datastore()
这两个方法,把它的属性转换成一个存储在数据库里的 int
。因为这个 int
是 Python 的基本类型,所以看起来你应该可以创建一个 FuzzyDateProperty
的 ListProperty
。那该怎么做呢?
在我的具体情况下,我定义了一个类和一些辅助函数,用来整齐地序列化和反序列化它的属性。我想把这个类封装成一个 db.Property
,而不是让实现者自己处理这个类和模型属性之间的关系。
3 个回答
你不能这样做——ListProperty 需要的是基本的 Python 数据类型,而不是属性类。同时,属性类是需要和模型(Model)关联的,而不是和其他属性关联。
根据类型和属性类文档
App Engine 的数据存储支持一组固定的值类型,用于数据实体的属性。属性类可以定义新的类型,这些类型可以在底层值类型之间进行转换,并且这些值类型可以直接与 Expando 动态属性和ListProperty聚合属性模型一起使用。
我理解这段话的意思是,你应该可以直接把扩展的 db.Property 作为 ListProperty 的 item_type 来使用。但是,有一个已记录的问题表明情况可能并非如此。
假设这样做不行,我认为接下来最好的办法可能是创建一个 ListProperty 的子类,并手动添加获取器、设置器和迭代器,基于“get_value_for_datastore”和“make_value_from_datastore”这两个函数,来处理包含“FuzzyDateProperty”成员的列表。
根据@mjhm和@Nick的建议,我创建了一个名为ListProperty的子类,可以接受任何类型的类。我已经把这个通用版本上传到了GitHub,叫做ObjectListProperty。这样做是为了让使用起来更简洁,而不是用多个并行的ListProperty。
ObjectListProperty在获取和放入模型时,会自动处理数据的序列化和反序列化。它有一个内部的方法,可以处理简单的对象,但如果对象比较复杂,只要它们自己定义了序列化的方法,ObjectListProperty也能处理。下面是一个简单的例子:
from object_list_property import ObjectListProperty class Animal(): """ A simple object that we want to store with our model """ def __init__(self, species, sex): self.species = species self.sex = sex if sex == 'male' or sex == 'female' else 'unknown' class Zoo(db.Model): """ Our model contains of list of Animal's """ mammals = ObjectListProperty(Animal, indexed=False) class AddMammalToZoo(webapp.RequestHandler): def post(self): # Implicit in get is deserializing the ObjectListProperty items zoo = Zoo.all().get() animal = Animal(species=self.request.get('species'), sex=self.request.get('sex') ) # We can use our ObjectListProperty just like a list of object's zoo.mammals.append(animal) # Implicit in put is serializing the ObjectListProperty items zoo.put()