Thank you Michael, that's for the catch-the-error part. How about the set-relations-right part, if I decided to go with my fix-as-you go recipe ? do you have any idea ? the dictionary approach seems good, but I still am curious about how to set relations generically on models. I think I'll use it somewhere else in my code.
By the way, I think the pseudo should have been : instance = next_instance_from_csv() try: session.commit() except IntegrityError,e : session.rollback() if e.orig == UniqueConstraintError : original_instance = ModelClass.get(instance.id) for relation_name in instance.get_relation_names() : # Is this correct ? path_to_attribute= "mapper."+ relation +".inverse" # I don't know where to find this ? instance.set_attribute(path_to_attribute,original_instance) session.commit() class BaseModel (DeclarativeBase): ... def set_attribute(self,path,value): nodes = path.explode(".") current_node = self for next_node in nodes : current_node = getattr(current_node,next_node,None) if not current_node: raise InvalidAttribute set_attribute(current_node,value) # sqla's set_attribute, for whatever reason... Y.Chaouche --- On Thu, 9/9/10, Michael Bayer <mike...@zzzcomputing.com> wrote: > From: Michael Bayer <mike...@zzzcomputing.com> > Subject: Re: [sqlalchemy] Copying instances from old to new schema DB > To: sqlalchemy@googlegroups.com > Date: Thursday, September 9, 2010, 5:59 AM > > On Sep 9, 2010, at 6:31 AM, chaouche yacine wrote: > > > Hello list, > > > > My schema has changed, and now I want to retrieve my > old data (of the old schema) to the new database (with the > new schema) from csv files (I export the tables of the old > database to csv files and then load those csv files to the > new database with some column mapping and some gap filling > for new columns) > > > > The problem is that my new schema have a > UniqueConstraint for some tables (like : the name column of > the city table should be unique within a country). This > constraint was not present in the old schema and data is > corrupt (two cities with the same name in the same country). > So when I try to insert them in the new database, I have > IntegrityErrors. > > > > The solution I thought of was : > > * Catch the IntegrityError exception > > * If it's a problem on a UniqueConstraint, then the > exception was raised because I tried to insert instance B > that has the same "key" as instance A that was inserted > before. > > * So for all children of B (B's relations), set their > parent to A. For example, for all citizens of B, set their > city to A, beause A and B ought to be the same. > > * Then, safely ignore B and move on to the next > instance. > > > > Here's what has been done so far (that works, I just > use psuedo code for "illustration" purpose. If necessary, > you can look at the actual attached source files): > > > > line = > csvloader.next_row() > > ModelClass = get_current_model() > > instance = > ModelClass.create_instance(**(to_dict(line))) > > session.add(instance) > > > > I wish I could do something like this : > > try: > > session.commit() > > except IntegrityError,e : > > session.rollback() > > errror = get_error() > > if type_of(error) == > UniqueConstraintError : > > original_instance = > ModelClass.get(instance.id) > > for relation in > instance.get_relations() : > > # Is this > correct ? > > > instance.relation.inverse = original_instance > > session.commit() > > > > My questions are : how to write get_error, type_of, > where to get UniqueContraintError, how to write > get_relations, how to set the inverse of a relation (is > instance.realtion.inverse the right thing to set ?) and is > this approach correct ? > > There's no portable way to detect "unique constraint" > errors across DBAPIs, you'd have to catch the specific error > that you've observed your DBAPI emits as well as the > message/codes contained within it, and code against > that. SQLAlchemy wraps DBAPI exceptions in > its own same-named wrapper and the object emitted by the > DBAPI is available under the ".orig" member. > > One improvement to the recipe would be if you used > savepoints, if supported by your database, so that when you > issue rollback() inside a savepoint block, the whole > transaction isn't rolled back and you can maintain the whole > operation in one transaction. The session > can start a savepoint using begin_nested(). > > When I do csv loads like these however I usually load the > full list of identifiers to be checked into memory ahead of > time. If the csv is less than 100K rows and represents > the full table of data, I just load the whole thing into a > dictionary, formatted according to whatever "these are the > fields that are unique" I'm dealing with, and consult the > dictionary as I go along. Otherwise, I load > individual blocks of data in as I scan through portions of > the csv (like, give me all the records where id in (a, b, c, > d, e, f, g, ...) for this block). There's > nothing "wrong" with the "catch-the-error" approach except > that I like an entire operation to be in a single > transaction, and its usually simpler and faster just to work > with a Python dictionary. > > > > > > > > > > > > > -- > > You received this message because you are subscribed > to the Google Groups "sqlalchemy" group. > > To post to this group, send email to sqlalch...@googlegroups.com. > > To unsubscribe from this group, send email to > sqlalchemy+unsubscr...@googlegroups.com. > > For more options, visit this group at > > http://groups.google.com/group/sqlalchemy?hl=en. > > > > <loadCSV.py><db.py> > > -- > You received this message because you are subscribed to the > Google Groups "sqlalchemy" group. > To post to this group, send email to sqlalch...@googlegroups.com. > To unsubscribe from this group, send email to > sqlalchemy+unsubscr...@googlegroups.com. > For more options, visit this group at > http://groups.google.com/group/sqlalchemy?hl=en. > > -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To post to this group, send email to sqlalch...@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.