Использование Property Builtin с моделью GAE Datastore - PullRequest
0 голосов
/ 20 февраля 2010

Я хочу сделать атрибуты свойств модели GAE. Причина в том, что перед тем, как сохранить значение, нужно преобразовать значение в верхний регистр. Для простого класса Python я бы сделал что-то вроде:

Foo(db.Model):
    def get_attr(self):
       return self.something
    def set_attr(self, value):
       self.something = value.upper() if value != None else None
    attr = property(get_attr, set_attr)

Однако GAE Datastore имеет собственную концепцию класса Property, я изучил документацию и, похоже, я могу переопределить get_value_for_datastore(model_instance) для достижения своей цели. Тем не менее, я не знаю, что такое model_instance и как извлечь из него соответствующее поле.

Является ли переопределение классов свойств GAE правильным способом обеспечения функциональности, аналогичной принципам получения / установки? Если да, то как это сделать?

Добавлено:

Одна потенциальная проблема переопределения get_value_for_datastore, о которой я думаю, это то, что он не может быть вызван до того, как объект был помещен в хранилище данных. Следовательно, получение атрибута перед сохранением объекта приведет к неверному значению.

Ответы [ 2 ]

3 голосов
/ 20 февраля 2010

Подклассы * Свойство класса GAE особенно полезно, если вам нужно более одного "поля" с похожим поведением в одной или нескольких моделях. Не волнуйтесь, get_value_for_datastore и make_value_from_datastore будут вызываться в любом магазине и при получении соответственно - поэтому, если вам нужно сделать что-нибудь необычное (включая, помимо прочего, верхний регистр строки, что на самом деле не все , что причудливо ;-), переопределение этих методов в вашем подклассе просто прекрасно.

Редактировать : давайте рассмотрим пример кода (за вычетом импорта и main):

class MyStringProperty(db.StringProperty):
    def get_value_for_datastore(self, model_instance):
        vv = db.StringProperty.get_value_for_datastore(self, model_instance)
        return vv.upper()

class MyModel(db.Model):
    foo = MyStringProperty()

class MainHandler(webapp.RequestHandler):

    def get(self):
        my = MyModel(foo='Hello World')
        k = my.put()
        mm = MyModel.get(k)
        s = mm.foo
        self.response.out.write('The secret word is: %r' % s)

Это показывает, что строка была в верхнем регистре в хранилище данных - но если вы измените вызов get на простой mm = my, вы увидите, что экземпляр в памяти не был затронут.

Но сам экземпляр db.Property является дескриптором - его упаковка во встроенный property (совершенно другой дескриптор) не будет хорошо работать с хранилищем данных (например, вы не можете писать запросы GQL основанные на именах полей, которые на самом деле не являются экземплярами db.Property, а являются экземплярами property - эти поля не в хранилище данных!).

Поэтому, если вы хотите работать с хранилищем данных и для экземпляров Model, которые никогда не были в хранилище данных и обратно, вам придется выбрать two имена для того, что логически «одно и то же» поле - одно - это имя атрибута, который вы будете использовать в экземплярах модели в памяти, и этот может быть встроенным property; другой - это имя атрибута, который заканчивается в хранилище данных, и он должен быть экземпляром db.Property подкласса , а - это второе имя, которое вам нужно будет использовать в запросах , Конечно, методы, лежащие в основе первого имени, должны читать и писать второе имя, но вы не можете просто «спрятать» последнее, потому что это имя будет в хранилище данных, и поэтому это имя будет иметь смысл для запросы!

1 голос
/ 25 февраля 2010

То, что вы хотите, это DerivedProperty .Процедура написания одного изложена в этом посте - она ​​аналогична описанной Алексом, но переопределив get вместо get_value_for_datastore, вы избежите проблем с необходимостью записи в хранилище данных для его обновления.Моя библиотека aetycoon содержит ее и другие полезные свойства.

...