How do I create a custom column type that exposes multiple attributes to the class

32 views
Skip to first unread message

Paddy Mullen

unread,
Mar 12, 2012, 5:06:08 PM3/12/12
to sqlal...@googlegroups.com
I am trying to create a column that stores sha1sums of content, and
allows easy programatic access of that content.  I would like my table
definition to look like this

class Picture(Base):
   content = sa.Column('content_sha1sum', DataColumn(se))

I would like to be able to create instances of pictures like this

p = Picture()
p.content(binary_image_string)

I only want to save the sha1sum to the database, DataColumn takes care
of computing the sha1sum, and actually saving the content to s3 or the
filesystem.  I also want DataColumn to be a deferred column, I can do
that with deferred

All good so far.

What I can't do, or can't do cleanly is figure out how to access the
sha1sum behind content

p = s.query(Picture).all().first()

p.content_sha1sum
p.content_direct_url

Where direct_url is a function of the sha1sum.  The problem with a
custom column is, I can't make sha1sum loading eager and the call to
s3/filesystem lazy, this means that every re-hydration of a Picture
requires a read from the filesystem.

There are a couple of ways that I could go.  First would be to store
the sha1sum directly as a regular String column, and create properties
of names "content" and "content_direct_url".  Another method would be
to use a mixin, but that is a bit ugly.

What I really want is a way to add all 3 properties with a single
line.  I'm willing to modify DeclarativeMeta .

Any thoughts?

Michael Bayer

unread,
Mar 13, 2012, 2:06:59 PM3/13/12
to sqlal...@googlegroups.com

So really the problem here is not the mechanics of things, you just want a very particular way of declaring it in your model.

I'm a strong proponent of mixins, but I suppose here the "ugly" part is that the mixin doesn't really grant a nice way of defining what the name of the column/attribute would be, and you just want a single attribute that becomes several.

So if you really want totally "magic" kinds of configuration, that is, you set up just one attribute on the class that magically creates two others, the straight path to this, without having to hack into metaclasses, is to use events. The blog post at http://techspot.zzzeek.org/2011/05/17/magic-a-new-orm/ illustrates a technique for doing this. Using the "mapper_configured" event you receive an event whenever a mapper is finished initializing itself. At that point you can scan through the class and/or mapping and apply any additional things you want to apply.

Another path is to override __mapper_cls__, which is a way of receiving a hook as soon as declarative sets up the mapping for the class. An example of using this method is in the distro in examples/declarative_reflection/. You'd use similar techniques, and at that stage you can also augment what gets sent to mapper() and add columns directly on the Table. The advantage to __mapper_cls__ is that you get to set up the class early, while the advantage to the mapper_configured event is that the approach remains discrete and separate from everything else going on, and also has access to the full configuration of other mappers.

Reply all
Reply to author
Forward
0 new messages