On 5/13/15 5:33 PM, Bruno Grande wrote:
I was looking for a way of typecasting attributes that are mapped to
Integer columns as Python integers without having to commit to the
database first. On the IRC channel, I was pointed towards simple
validators and the @validates decorator. While this works,
implementing validation using this approach for all integer attributes
across all classes seems inefficient.
I then looked into AttributeEvents with the idea of adding a listener
to the base class, but I can't seem to figure out a way for have the
listener listen to all attribute changes. The documentation
<http://docs.sqlalchemy.org/en/latest/orm/events.html#sqlalchemy.orm.events.AttributeEvents.set>
only gives examples for listening to specific attributes (see example
code below pulled from documentation).
|
from sqlalchemy import event
@event.listens_for(SomeClass.some_attribute, 'set')
def receive_set(target, value, oldvalue, initiator):
# ... (event handling logic) ...
|
Hence, I was wondering if any of you would have a clever and
straightforward way of achieving type validation on all classes (at
least for integers for now). Thanks!
*Extra Information*
Python 2.7.8
SQLAlchemy 0.9.8
So first off, in Python we do have the option of overriding a builtin
method called __setattr__(), which if you really wanted to intercept
most attribute set events, you could just do that. This is heavy-handed
though because it is called for all attribute sets everywhere and it
would spend a lot of time filtering out attributes it doesn't care about.
Secondly, @validates and AttributeEvents are two versions of the same
thing - @validates is a shortcut for AttributeEvents, and the
AttributeEvents listener is set up on a per-attribute basis. So there's
not too much difference except how these are configured, and using the
AttributeEvents is better for programmatic attachment. You can also set
up such a listener for all mapped attributes everywhere, but again this
is too broad and such a listener again wastes lots of time filtering on
which events it cares about.
With that information out of the way, the general strategy to listen to
events on things that are mapped such that the things which we're
listening to is also dynamic / programmatic is to apply event listeners
to the attributes we care about. There's more events that we make use
of in order to set up event listeners at the moment that these various
attributes and other things are mapped. There are a lot of ways to
catch such events, but the most easy one that was added mostly for this
purpose is known as the "attribute_instrument" event, which is called
whenever a new class attribute becomes part of a SQLAlchemy mapping.
This is a good place where you can check how this attribute is mapped
and make decisions about what kind of validation it should have. Two
examples are provided, one which illustrates how to apply a listener to
all the events associated with a base class, that is at
http://docs.sqlalchemy.org/en/rel_1_0/_modules/examples/custom_attributes/listen_for_events.html,
and there's also a recipe which I think is nicer that sets up validators
based on the column types, such as your Integer here, that is at
https://bitbucket.org/zzzeek/sqlalchemy/wiki/UsageRecipes/ValidateOnType.
Best regards,
Bruno
--
You received this message because you are subscribed to the Google
Groups "sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to [email protected]
<mailto:[email protected]>.
To post to this group, send email to [email protected]
<mailto:[email protected]>.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.