My issue with SQLA validators is that they don't allow inconsistent
state even on fields of a single object, which makes multi-field
validation impossible.

Eg. imagine you have fields tax_id and country_code on a customer
object. For country code 'us', tax_id should be 9 digits long; for
country code 'ca', tax_id should be 15 digits long . If you create
appropriate validators on both fields, you will never be able to
change either the tax_id or country_code of any customer object.

The solution would be to allow inconsistent objects but do validation
just before commit. I've been planning on implementing such validation
for a project I'm working on, so any suggestions are welcome.

On Sep 22, 5:30 pm, Randall Nortman <[email protected]> wrote:
> In my application, I have a set of tables that model parts of what are
> conceptually composite objects, and I need to validate that the state
> of the objects is coherent before committing them to the database.  In
> the course of building up the network of objects, the state may be
> temporarily inconsistent (because it will, in general, be impossible
> to maintain consistency at every step of the process), but I want to
> make sure it is consistent by the time it hits the database.  I think
> the answer is to make a SessionExtension and use before_commit(), but
> I still have some questions about exactly how that works.
>
> To make the question concrete, I have a one-to-many relationship, and
> the relevant state is the state of the parent+children composite.  Any
> change to a child's attributes needs to trigger re-validation of the
> parent, and obviously any change in membership in the collection of
> children needs to trigger revalidation.  In particular, if a child
> moves from one parent to another, then *both* parents must be re-
> validated before the transaction is committed.  All this validation
> needs to occur even though the parent table is not modified in any of
> those cases.  And I think I will likely want this to work also in a
> many-to-many relationship, where any change to the association table
> should trigger validation of all related (or newly unrelated) objects.
>
> Furthermore, I want to work with these objects as individual Parent
> and Child objects, not a single ParentWithChildren object.  Or at a
> minimum, I want to be able to pass around and modify Child objects on
> their own; if I get the Children every time I ask for the Parent,
> that's fine.
>
> The @validates decorator is largely useless for this purpose, as it
> validates a particular attribute of a particular class, and it gets
> called at the wrong time, and in the case of collections, only gets
> called on append events, not remove events (afaict).
>
> So if I do this with a SessionExtension.before_commit(), I would have
> to iterate through the new, dirty, and deleted instances lists,
> inspect the type of each instance, and do whatever is required.  I am
> not sure, though, how to handle the case of a change in membership in
> the parent/child relationship -- the child instance that is present in
> the dirty list will have only the new parent on it -- how do I find
> out what the old parent was, so I can validate it?  If a flush has
> already occurred, the old value is already lost in the context of the
> current transaction, and I think that if I open a new transaction
> inside a before_commit() validator I'm just asking for trouble.  Do I
> need to instrument the Child class with a descriptor that tracks
> changes to the parent and remembers the old parent?  Or can I set the
> cascade option in such a way that the old parent will end up in the
> dirty list, even though there are no changes to its underlying table,
> and in fact it may never have been explicitly loaded into the
> session?  (I must admit to be somewhat unsure of what the different
> cascade options do -- but they don't seem to be useful for tracking
> something like this.)
>
> And lastly, what do I do inside before_commit() if I want to prevent
> the commit from proceeding?  Do I just raise an exception?  Any
> particular type of exception, or is it my choice?
>
> Sorry for the long question, and thanks for any assistance,
>
> Randall
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to