I would like to use __setattr__ in a sqlalchemy class to handle
certain fields, but have not been able to figure out the
appropriate syntax. Normally I would have something like:
class MyClass(MyOtherClass):
def __setattr__(self, key, val):
if key == 'field1':
# do something
elif key == 'field2':
# do something else
else: # default
MyOtherClass.__setattr__(self, key, val)
How would one do this using sqlalchemy with something like:
from sqlalchemy import *
from sqlalchemy import *
myclass_table = Table(...)
Class MyClass(object):
# stuff here
mapper(MyClass, myclass_table, ...)
Bill
--
INTERNET: bi...@celestial.com Bill Campbell; Celestial Software LLC
URL: http://www.celestial.com/ PO Box 820; 6641 E. Mercer Way
FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
Cutting the space budget really restores my faith in humanity. It
eliminates dreams, goals, and ideals and lets us get straight to the
business of hate, debauchery, and self-annihilation. -- Johnny Hart
>
> I am just getting up to speed with sqlalchemy, and spent a good
> part of last weekend reading the on-line documentation, as well
> as looking into the sources.
>
> I would like to use __setattr__ in a sqlalchemy class to handle
> certain fields, but have not been able to figure out the
> appropriate syntax. Normally I would have something like:
>
> class MyClass(MyOtherClass):
> def __setattr__(self, key, val):
> if key == 'field1':
> # do something
> elif key == 'field2':
> # do something else
> else: # default
> MyOtherClass.__setattr__(self, key, val)
>
> How would one do this using sqlalchemy with something like:
>
> from sqlalchemy import *
> from sqlalchemy import *
>
> myclass_table = Table(...)
>
> Class MyClass(object):
> # stuff here
>
> mapper(MyClass, myclass_table, ...)
>
implementing your own __setattr__ by itself is not an issue, as long
as you ultimately call the __setattr__ present on "object" to set the
attribute value (assuming you want the value to be set). In other
words, you can't populate __dict__ directly since SQLAlchemy relies on
Python descriptors to issue events and track changes. The example
you have above would be fine (assuming you don't want "field1" and
"field2" to actually be assigned).
If you're just looking for very basic attribute setter/getter
behavior, we also encourage the usage of user-defined Python
descriptors which can be integrated into a mapping using the synonym()
function. In your case it depends upon what you are specifically
looking to accomplish that would help make the choice here.
For more dramatic class re-engineering, there is an option to
completely redefine how SQLAlchemy instruments classes which is being
worked on in a development branch right now, but so far this sounds
like more than you need.
Setting those fields is in the ``# stuff here'' :-).
>If you're just looking for very basic attribute setter/getter
>behavior, we also encourage the usage of user-defined Python
>descriptors which can be integrated into a mapping using the synonym()
>function. In your case it depends upon what you are specifically
>looking to accomplish that would help make the choice here.
My purpose is to be able to call general setattr from things like
screen processing routines where I have an arbitrary fieldname
and value to update, and to be able to handle cases where other
tables may need updating (e.g. changing a quantity in an order
detail line requires updating extensions, updating quantity
committed in an inventory record, etc.). It would also handle
simple edits of input values, converting to upper or lower case,
reformatting phone numbers, and similar edits.
I didn't understand the possibilities of the synonum mapping on
my first reading of the mapper documentation (and am not sure
that I understand it yet without playing with it). In the
documentation, the ``email'' attribute is the one in the database
table, and ``_email'' is a local attribute in the class?
>For more dramatic class re-engineering, there is an option to
>completely redefine how SQLAlchemy instruments classes which is being
>worked on in a development branch right now, but so far this sounds
>like more than you need.
I have a lot of learning to do before I can get into that.
Bill
--
INTERNET: bi...@celestial.com Bill Campbell; Celestial Software LLC
URL: http://www.celestial.com/ PO Box 820; 6641 E. Mercer Way
FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
Never blame a legislative body for not doing something. When they do
nothing, that don't hurt anybody. When they do something is when they
become dangerous. -- Will Rogers
Thanks for the pointer. That looks interesting.
BTW: The svn link above appears to be obsolete. There's a new
one on the gafol.net site.
Bill
--
INTERNET: bi...@celestial.com Bill Campbell; Celestial Software LLC
URL: http://www.celestial.com/ PO Box 820; 6641 E. Mercer Way
FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
My reading of history convinces me that most bad government results
from too much government. --Thomas Jefferson.
>
> My purpose is to be able to call general setattr from things like
> screen processing routines where I have an arbitrary fieldname
> and value to update, and to be able to handle cases where other
> tables may need updating (e.g. changing a quantity in an order
> detail line requires updating extensions, updating quantity
> committed in an inventory record, etc.). It would also handle
> simple edits of input values, converting to upper or lower case,
> reformatting phone numbers, and similar edits.
if you're looking to set attributes generically from the outside, you
could just use the regular python setattr function - setattr(object,
key, value).
the case where you need something to happen in response to a setattr
you could do the way you proposed, using __setattr__(), or by using
descriptors. We usually point to using descriptors since they are
defined on a per-attribute basis, rather than needing to build a
complicated if/else block inside of __setattr__.
>
>
> I didn't understand the possibilities of the synonum mapping on
> my first reading of the mapper documentation (and am not sure
> that I understand it yet without playing with it). In the
> documentation, the ``email'' attribute is the one in the database
> table, and ``_email'' is a local attribute in the class?
in the example, the database column is called "email", sqlalchemy maps
the "_email" attribute to that column, then the user-facing "email"
descriptor does what it needs to and then populates the "underlying"
value using the "_email" attribute. The only reason the synonym()
function is used at all is so that the "email" attribute is available
for querying - i.e. query.filter(MyAddress.email ==
'f...@bar.com')...it doesn't affect the "email" attribute beyond that.
>> For more dramatic class re-engineering, there is an option to
>> completely redefine how SQLAlchemy instruments classes which is being
>> worked on in a development branch right now, but so far this sounds
>> like more than you need.
>
> I have a lot of learning to do before I can get into that.
doesn't sound like its needed here.
My intention is to use the normal setattr calls, which I assume call the
underlying setattr functions if they are defined.
>the case where you need something to happen in response to a setattr
>you could do the way you proposed, using __setattr__(), or by using
>descriptors. We usually point to using descriptors since they are
>defined on a per-attribute basis, rather than needing to build a
>complicated if/else block inside of __setattr__.
I may be a bit thick here, but I don't understand descriptors, and don't
find anything in the document other than engine_descriptions or database
specific descriptors.
In practice, I probably wouldn't use complex if/else (although I have some
monster switch statements in some C programs I that do similar things with
database updates :-). I should probably be using stored procedures and
triggers for this (postgres back end), but at this point I'm trying to get
my head around sqlalchemy.
Bill
--
INTERNET: bi...@celestial.com Bill Campbell; Celestial Software LLC
URL: http://www.celestial.com/ PO Box 820; 6641 E. Mercer Way
FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
...I'm not one of those who think Bill Gates is the devil. I simply
suspect that if Microsoft ever met up with the devil, it wouldn't need an
interpreter. -- Nick Petreley
>
> I may be a bit thick here, but I don't understand descriptors, and
> don't
> find anything in the document other than engine_descriptions or
> database
> specific descriptors.
descriptors are a Python thing, which are used to turn an ordinary
instance attribute into a getter/setter function:
http://docs.python.org/ref/descriptors.html
and usually, descriptors are made more easily using the "property()"
function, which is described with a little example at : http://docs.python.org/lib/built-in-funcs.html
PJE makes the case for the "property" builtin in his well-known post
"Python is not Java" : http://dirtsimple.org/2004/12/python-is-not-java.html
- mike
Many thanks Mike.
I've only been programming python for about four years now, and I
have not gotten deep into what I consider the fancier stuff (nor,
in the twenty or so years I did most of my work in perl did I
ever get into the areas that people like Damian Conway do :-).
Bill
--
INTERNET: bi...@celestial.com Bill Campbell; Celestial Software LLC
URL: http://www.celestial.com/ PO Box 820; 6641 E. Mercer Way
FAX: (206) 232-9186 Mercer Island, WA 98040-0820; (206) 236-1676
If the personal freedoms guaranteed by the Constitution inhibit the
government's ability to govern the people, we should look to limit those
guarantees. -- President Bill Clinton, August 12, 1993