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 -~----------~----~----~----~------~----~------~--~---
