Ich versuche herauszufinden, wie man eine einfache schreibgeschützte Eigenschaft abbildet, und lasse diese Eigenschaft auslösen, wenn ich in der Datenbank speichere.SQLAlchemy - wie man gegen eine schreibgeschützte (oder berechnete) Eigenschaft abbildet
Ein künstliches Beispiel sollte dies verdeutlichen. Zuerst wird eine einfache Tabelle:
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),
)
Was ich tun möchte, eine Klasse mit einer Nur-Lese-Eigenschaft eingerichtet ist, die in die calculated_value Spalte für mich einsetzen, wenn ich session.commit() aufrufen ...
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
nach den sqlalchemy docs, ich denke, soll ich dies abzubilden, wie so:
mapper(Foo, foo_table, properties = {
'calculated_value' : synonym('_calculated_value', map_column=True)
})
Das Problem dabei ist, dass _calculated_ Der Wert ist None, bis Sie auf die Eigenschaft comprected_value zugreifen. Es scheint, dass SQLAlchemy die Eigenschaft beim Einfügen in die Datenbank nicht aufruft, also bekomme ich stattdessen einen None-Wert. Was ist der richtige Weg, dies zuzuordnen, so dass das Ergebnis der Eigenschaft "calcted_value" in die Spalte "calcted_value" der foo-Tabelle eingefügt wird?
OK - Ich bearbeite diesen Beitrag, falls jemand anders dieselbe Frage hat. Was ich getan habe, war eine MapperExtension. Lassen Sie mich Ihnen ein besseres Beispiel zusammen mit Nutzung der Erweiterung:
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)
Und das ist, wie Sie diese verwenden. Nehmen wir an, Sie haben eine Klasse mit mehreren schreibgeschützten Eigenschaften, die vor dem Einfügen in die Datenbank ausgelöst werden müssen. Ich gehe hier davon aus, dass Sie für jede dieser schreibgeschützten Eigenschaften eine entsprechende Spalte in der Datenbank haben, die Sie mit dem Wert der Eigenschaft füllen möchten. Sie sind immer noch ein Synonym für jede Eigenschaft einzurichten, aber Sie verwenden, um die Mapper Erweiterung oben, wenn Sie das Objekt Karte:
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)
})
Interessant.Auch wenn ich das etwas anders gelöst habe, habe ich dies als Antwort markiert, weil es funktionieren sollte. Je mehr ich über SQLAlchemy lerne, desto mehr mag ich es! –