Я пытаюсь выяснить, как сопоставить простое свойство, доступное только для чтения, и заставить это свойство срабатывать при сохранении в базу данных.
Придуманный пример должен прояснить это. Сначала простая таблица:
meta = MetaData()
foo_table = Table('foo', meta,
Column('id', String(3), primary_key=True),
Column('description', String(64), nullable=False),
Column('calculated_value', Integer, nullable=False),
)
То, что я хочу сделать, это настроить класс со свойством только для чтения, которое будет вставляться в столбец calc_value для меня при вызове session.commit () ...
import datetime
def Foo(object):
def __init__(self, id, description):
self.id = id
self.description = description
@property
def calculated_value(self):
self._calculated_value = datetime.datetime.now().second + 10
return self._calculated_value
Согласно документации по sqlalchemy, я думаю Я должен отобразить это так:
mapper(Foo, foo_table, properties = {
'calculated_value' : synonym('_calculated_value', map_column=True)
})
Проблема в том, что _calculated_value равен None до тех пор, пока вы не получите доступ к свойству Calculated_value. Похоже, что SQLAlchemy не вызывает свойство при вставке в базу данных, поэтому вместо этого я получаю значение None. Как правильно отобразить это так, чтобы результат свойства "selected_value" был вставлен в столбец "Calculate_value" таблицы foo?
ОК - я редактирую это сообщение на тот случай, если у кого-то еще возникнет тот же вопрос. В итоге я использовал MapperExtension. Позвольте мне привести вам лучший пример с использованием расширения:
class UpdatePropertiesExtension(MapperExtension):
def __init__(self, properties):
self.properties = properties
def _update_properties(self, instance):
# We simply need to access our read only property one time before it gets
# inserted into the database.
for property in self.properties:
getattr(instance, property)
def before_insert(self, mapper, connection, instance):
self._update_properties(instance)
def before_update(self, mapper, connection, instance):
self._update_properties(instance)
И вот как вы это используете. Допустим, у вас есть класс с несколькими свойствами только для чтения, которые должны срабатывать перед вставкой в базу данных. Здесь я предполагаю, что для каждого из этих свойств только для чтения у вас есть соответствующий столбец в базе данных, который вы хотите заполнить значением свойства. Вы по-прежнему будете устанавливать синоним для каждого свойства, но при отображении объекта вы используете расширение mapper, указанное выше:
class Foo(object):
def __init__(self, id, description):
self.id = id
self.description = description
self.items = []
self.some_other_items = []
@property
def item_sum(self):
self._item_sum = 0
for item in self.items:
self._item_sum += item.some_value
return self._item_sum
@property
def some_other_property(self):
self._some_other_property = 0
.... code to generate _some_other_property on the fly....
return self._some_other_property
mapper(Foo, metadata,
extension = UpdatePropertiesExtension(['item_sum', 'some_other_property']),
properties = {
'item_sum' : synonym('_item_sum', map_column=True),
'some_other_property' : synonym('_some_other_property', map_column = True)
})