Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy: add a child in many-to-many relationship by IDs

I am looking for a way to add a "Category" child to an "Object" entity without wasting the performance on loading the child objects first.

The "Object" and "Category" tables are linked with many-to-many relationship, stored in "ObjectCategory" table. The "Object" model is supplied with the relationsip:

categories = relationship('Category', secondary = 'ObjectCategory', backref = 'objects')

Now this code works just fine:

obj = models.Object.query.get(9)
cat1 = models.Category.query.get(22)
cat2 = models.Category.query.get(28)
obj.categories.extend([cat1, cat2])

But in the debug output I see that instantiating the obj and each category costs me a separate SELECT command to the db server, in addition to the single bulk INSERT command. Totally unneeded in this case, because I was not interested in manipulating the given category objects. Basically all I need is to nicely insert the appropriate category IDs.

The most obvious solution would be to go ahead and insert the entries in the association table directly:

db.session.add(models.ObjectCategory(oct_objID=9, oct_catID=22))
db.session.add(models.ObjectCategory(oct_objID=9, oct_catID=28))

But this approach is kind of ugly, it doesn't seem to use the power of the abstracted SQLAlchemy relationships. What's more it produces separate INSERT for every add(), vs the nice bulk INSERT as in the obj.categories.extend([list]) case. I imagine there could be some lazy object mode that would let the object live with only it's ID (unverified) and load the other fields only if they are requested. That would allow adding children in one-to-many or many-to-many relationships without issuing any SELECT to the database, yet letting to use the powerful ORM abstraction (ie, treating the list of children as a Python list).

How should I adjust my code to carry out this task using the power of SQLAlchemy but being conservative on the database use?

like image 226
Passiday Avatar asked Apr 07 '14 13:04

Passiday


1 Answers

Do you have a ORM mapping for the ObjectCategory table? If so you could create and add ObjectCategory objects:

session.add(ObjectCategory(obj_id=9, category_id=22)
session.add(ObjectCategory(obj_id=9, category_id=28)
like image 82
codeape Avatar answered Oct 21 '22 07:10

codeape