views:

162

answers:

2

Hello there,

I have an ORM mapped object, that I want to update. I have all attributes validated and secured in a dictionary (keyword arguments). Now I would like to update all object attributes as in the dictionary.

for k,v in kw.items():
    setattr(myobject, k, v)

doesnt work (AttributeError Exception), thrown from SQLAlchemy.

myobject.attr1 = kw['attr1']
myobject.attr2 = kw['attr2']
myobject.attr3 = kw['attr3']

etc is horrible copy paste code, I want to avoid that.#

How can i achieve this? SQLAlchemy already does something similar to what I want to do in their constructors ( myobject = MyClass(**kw) ), but I cant find that in all the meta programming obfuscated crap in there.

error from SA:

<<          if self.trackparent:
                   if value is not None:
                       self.sethasparent(instance_state(value), True)
                   if previous is not value and previous is not None:
                       self.sethasparent(instance_state(previous), False)
>>  self.sethasparent(instance_state(value), True)
AttributeError: 'unicode' object has no attribute '_sa_instance_state'
+2  A: 
myobject.__dict__.update(**kw)
SilentGhost
Hm sadly this doesnt work for SQLAlchemy. The __dict__ gets properly updated but SA doesnt seem to flag the object as "dirty" and persist it to the DB
Tom
+2  A: 

You are trying to assign a unicode string to a relation attribute. Say you have:

 class ClassA(Base):
     ...
     b_id = Column(None, ForeignKey('b.id'))
     b = relation(ClassB)

And you are trying to do:

 my_object = ClassA()
 my_object.b = "foo"

When you should be doing either:

 my_object.b_id = "foo"
 # or
 my_object.b = session.query(ClassB).get("foo")
Ants Aasma
i'll be damned. that was the solution.my setattr stuff works fine, when I convert kw['attr1'] = Session.query(MyClass).get(kw['attr1'])
Tom
The amazing stuff I just found out is also, that you can indeed assign an int to a relation attribute, i just tested it myself.myobject.b = 1 would work, if there is an object b with id = 1. Seems my validators screwed up, as the id obtained from the relation wasnt properly cast into int, but remained as unicode. Seems SA does like ints, but not unicodes assigned to relation properties
Tom
Strange, assigning an int to a relation should result in the same error.
Ants Aasma
I just tested it out, it does not work if I just cast kw['arg1'] = int(kw['arg1']) and then assign it via setattr(....). Before you posted your answer that solved all my problems, I changed it my code frustratedly to copy paste code, (added an "MyClass.update(**kw) method) and in this method i simply wrote self.my_relation_attr = kw['my_relation_attr'] which is still the same old unicode string. And that worked, strangely. It obviously took the u"4" and turned it into 5, and set the my_relation_attr to the matching mapped object with ID = 5
Tom