The easiest way is to use the tuple_ function provided by SQLAlchemy:
from sqlalchemy import tuple_ session.query(Foo).filter(tuple_(Foo.a, Foo.b, Foo.c).in_(items))
This works with PostgreSQL, but does not work with SQLite. Not sure about other database engines.
Fortunately, there is a workaround that should work on all databases.
Start by matching all the elements with the and_
expression:
conditions = (and_(c1=x, c2=y, c3=z) for (x, y, z) in items)
And then create a filter or_
, which covers all the conditions:
q.filter(or_(*conditions))
Here is a simple example:
#/usr/bin/env python from sqlalchemy import create_engine from sqlalchemy import Column, Integer from sqlalchemy.sql import and_, or_ from sqlalchemy.orm import sessionmaker from sqlalchemy.ext.declarative import declarative_base engine = create_engine('sqlite:///') session = sessionmaker(bind=engine)() Base = declarative_base() class Foo(Base): __tablename__ = 'foo' id = Column(Integer, primary_key=True) a = Column(Integer) b = Column(Integer) c = Column(Integer) def __init__(self, a, b, c): self.a = a self.b = b self.c = c def __repr__(self): return '(%d %d %d)' % (self.a, self.b, self.c) Base.metadata.create_all(engine) session.add_all([Foo(1, 2, 3), Foo(3, 2, 1), Foo(3, 3, 3), Foo(1, 3, 4)]) session.commit() items = ((1, 2, 3), (3, 3, 3)) conditions = (and_(Foo.a==x, Foo.b==y, Foo.c==z) for (x, y, z) in items) q = session.query(Foo) print q.all() q = q.filter(or_(*conditions)) print q print q.all()
What are the findings:
$ python test.py [(1 2 3), (3 2 1), (3 3 3), (1 3 4)] SELECT foo.id AS foo_id, foo.a AS foo_a, foo.b AS foo_b, foo.c AS foo_c FROM foo WHERE foo.a = :a_1 AND foo.b = :b_1 AND foo.c = :c_1 OR foo.a = :a_2 AND foo.b = :b_2 AND foo.c = :c_2 [(1 2 3), (3 3 3)]