自定义属性的ListProperty

1 投票
3 回答
1022 浏览
提问于 2025-04-16 07:18

有没有一种优雅的方式来使用 ListProperty 来存储一个子类的 db.Property 类型呢?

举个例子,FuzzyDateProperty 这个东西来自于 这个例子,它使用 get_value_for_datastore()make_value_from_datastore() 这两个方法,把它的属性转换成一个存储在数据库里的 int。因为这个 int 是 Python 的基本类型,所以看起来你应该可以创建一个 FuzzyDatePropertyListProperty。那该怎么做呢?

在我的具体情况下,我定义了一个类和一些辅助函数,用来整齐地序列化和反序列化它的属性。我想把这个类封装成一个 db.Property,而不是让实现者自己处理这个类和模型属性之间的关系。

3 个回答

1

你不能这样做——ListProperty 需要的是基本的 Python 数据类型,而不是属性类。同时,属性类是需要和模型(Model)关联的,而不是和其他属性关联。

2

根据类型和属性类文档

App Engine 的数据存储支持一组固定的值类型,用于数据实体的属性。属性类可以定义新的类型,这些类型可以在底层值类型之间进行转换,并且这些值类型可以直接与 Expando 动态属性和ListProperty聚合属性模型一起使用。

我理解这段话的意思是,你应该可以直接把扩展的 db.Property 作为 ListProperty 的 item_type 来使用。但是,有一个已记录的问题表明情况可能并非如此。

假设这样做不行,我认为接下来最好的办法可能是创建一个 ListProperty 的子类,并手动添加获取器、设置器和迭代器,基于“get_value_for_datastore”和“make_value_from_datastore”这两个函数,来处理包含“FuzzyDateProperty”成员的列表。

1

根据@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()

撰写回答