On Nov 22, 2010, at 6:17 PM, Torsten Landschoff wrote: > Hi again! > > Sorry for all the questions, here is another one. > > What I really would like to do is to read a chunk of data for a mapped > instance and disseminate that into a number of attributes (not the usual > one column <-> one attribute mapping). This could easily be done using > an orm.reconstructor. > > Writing to that data triggers an internal flag which I would like the > ORM to take into account to detect that the instance is dirty (even > better: signal the ORM at the same time that it is dirty). During flush, > I would like to have a orm.deconstructor ;-) method run that collects > the data from the instance attributes for flushing it to the database.
The simplest way to approach not using mutable types is to assign a new value to the attribute. So if you copied im.image = im.image.update(new data), that results in just a single comparison at flush time. If you expire() the attribute first, then the comparison is against NO_VALUE so would avoid a long comparison. You could make StoredImage.image a proxy object of some kind that replaces the contents of StoredImage._image, the real object, whenever an event occurs. Or, for more efficiency, StoredImage.image just adds itself to a set() somewhere when a change is detected, and stores the changes given in an internal dictionary - then you do a SessionExtension.before_flush(), look in the set() for all the StoredImages, then write their _image attribute with their changes. > > I am far from having this implemented. I tried starting with a simple > example using the MutableType mixin: > > from sqlalchemy import * > from sqlalchemy.orm import * > from sqlalchemy.types import TypeDecorator, MutableType > import Image > import ImageEnhance > import numpy > from cStringIO import StringIO > > engine = create_engine("sqlite:////tmp/test.db", echo=True) > > class _ImageType(TypeDecorator): > impl = LargeBinary > def process_bind_param(self, value, dialect): > im = Image.fromarray(value) > fakefile = StringIO() > im.save(fakefile, 'png') > return fakefile.getvalue() > def process_result_value(self, value, dialect): > fakefile = StringIO(value) > return numpy.array(Image.open(fakefile)) > > class ImageType(MutableType, _ImageType): > def copy_value(self, value): > print "creating a copy" > return numpy.copy(value) > def compare_values(self, x, y): > print "compare: {0} vs. {1}".format(id(x), id(y)) > result = (x == y).all() > print "result: {0}".format(result) > return result > > metadata = MetaData() > image_table = Table("images", metadata, > Column("id", Integer, primary_key=True), > Column("image", ImageType)) > metadata.create_all(engine) > > class StoredImage(object): > def __init__(self, fname): > self.image = numpy.array(Image.open(fname)) > > mapper(StoredImage, image_table) > > Session = sessionmaker(engine) > session = Session() > > images = session.query(StoredImage).all() > if images: > for im in images: > data = im.image > for row in xrange(len(data)): > for col in xrange(len(data[0])): > r, g, b = data[row][col] > data[row][col] = b, g, r > # Image.fromarray(im.image).show() > print "dirty", session.dirty > else: > im = StoredImage("/usr/share/backgrounds/Daisy.jpg") > session.add(im) > session.commit() > > > This lacks almost everything that I really want: > > o data is still in a single attribute > o no dirty flag handling, but full content comparison > o the comparison is run each time the ORM looks up its dirty instances. > > > Just pondering... > > Torsten > > -- > DYNAmore Gesellschaft fuer Ingenieurdienstleistungen mbH > Torsten Landschoff > > Office Dresden > Tel: +49-(0)351-4519587 > Fax: +49-(0)351-4519561 > > mailto:torsten.landsch...@dynamore.de > http://www.dynamore.de > > Registration court: Mannheim, HRB: 109659, based in Karlsruhe, > Managing director: Prof. Dr. K. Schweizerhof, Dipl.-Math. U. Franz > > -- > You received this message because you are subscribed to the Google Groups > "sqlalchemy" group. > To post to this group, send email to sqlalch...@googlegroups.com. > To unsubscribe from this group, send email to > sqlalchemy+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/sqlalchemy?hl=en. > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.