tags:

views:

128

answers:

2

Suppose I have table tags which has a field count that indicates how many items have been tagged with the given tag.

How do I increase this counter in SQLAlchemy after I add a new item with an existing tag?

With plain SQL I would do the following:

INSERT INTO `items` VALUES (...)
UPDATE `tags` SET count=count+1 WHERE tag_id=5

But how do I express count=count+1 in SQLAlchemy?

Thanks, Boda Cydo.

+1  A: 

If you have something like:

mytable = Table('mytable', db.metadata,
    Column('id', db.Integer, primary_key=True),
    Column('counter', db.Integer)
)

You can increment fields like this:

m = mytable.query.first()
m.counter = mytable.c.counter + 1

Or, if you have some mapped Models, you can write alternatively:

m = Model.query.first()
m.counter = Model.counter + 1

Both versions will return the sql statement you have asked for. But if you don't include the column and just write m.counter += 1, then the new value would be calculated in Python (and race conditions are likely to happen). So always include a column as shown in the two examples above in such counter queries.

Regards,
Christoph

tux21b
Thanks. But can you explain about race condition more? Did I understand you correctly that the first version would be safer than the second?
bodacydo
No. Both versions I've showed you are exactly the same (one uses mapped objects and the other tables). But the third statement with `+=` would result in `SET counter=4` instead of `SET counter=counter+1`. So you shouldn`t use the third `+=` version.
tux21b
Understood. Thanks for helping!
bodacydo
A: 

If you are using the SQL layer, then you can use arbitrary SQL expressions in the update statement:

conn.execute(tags.update(tags.c.tag_id == 5).values(count=tags.c.count + 1))

The ORM Query object also has an update method:

session.query(Tag).filter_by(tag_id=5).update({'count': Tag.count + 1})

The ORM version is smart enough to also update the count attribute on the object itself if it's in the session.

Ants Aasma