I’ve looked through the docs and I cant seem to find out how to do an OR query in SQLAlchemy. I just want to do this query.
SELECT address FROM addressbook WHERE city='boston' AND (lastname='bulger' OR firstname='whitey')
Should be something like
addr = session.query(AddressBook).filter(City == "boston").filter(????)
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
From the tutorial:
from sqlalchemy import or_ filter(or_(User.name == 'ed', User.name == 'wendy'))
Method 2
SQLAlchemy overloads the bitwise operators &, | and ~ so instead of the ugly and hard-to-read prefix syntax with or_() and and_() (like in Bastien’s answer) you can use these operators:
.filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))
Note that the parentheses are not optional due to the precedence of the bitwise operators.
So your whole query could look like this:
addr = session.query(AddressBook)
.filter(AddressBook.city == "boston")
.filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey'))
Method 3
or_() function can be useful in case of unknown number of OR query components.
For example, let’s assume that we are creating a REST service with few optional filters, that should return record if any of filters return true. On the other side, if parameter was not defined in a request, our query shouldn’t change. Without or_() function we must do something like this:
query = Book.query
if filter.title and filter.author:
query = query.filter((Book.title.ilike(filter.title))|(Book.author.ilike(filter.author)))
else if filter.title:
query = query.filter(Book.title.ilike(filter.title))
else if filter.author:
query = query.filter(Book.author.ilike(filter.author))
With or_() function it can be rewritten to:
query = Book.query
not_null_filters = []
if filter.title:
not_null_filters.append(Book.title.ilike(filter.title))
if filter.author:
not_null_filters.append(Book.author.ilike(filter.author))
if len(not_null_filters) > 0:
query = query.filter(or_(*not_null_filters))
Method 4
For SQLAlchemy ORM 2.0 both | and or_ are accepted.
from sqlalchemy.future import select
from sqlalchemy.sql import or_
query = select(User).where(or_(User.name == 'ed', User.name == 'wendy'))
print(query)
# also possible:
query = select(User).where((User.name == 'ed') | (User.name == 'wendy'))
print(query)
Method 5
This has been really helpful.
Here is my implementation for any given table:
def sql_replace(self, tableobject, dictargs):
#missing check of table object is valid
primarykeys = [key.name for key in inspect(tableobject).primary_key]
filterargs = []
for primkeys in primarykeys:
if dictargs[primkeys] is not None:
filterargs.append(getattr(db.RT_eqmtvsdata, primkeys) == dictargs[primkeys])
else:
return
query = select([db.RT_eqmtvsdata]).where(and_(*filterargs))
if self.r_ExecuteAndErrorChk2(query)[primarykeys[0]] is not None:
# update
filter = and_(*filterargs)
query = tableobject.__table__.update().values(dictargs).where(filter)
return self.w_ExecuteAndErrorChk2(query)
else:
query = tableobject.__table__.insert().values(dictargs)
return self.w_ExecuteAndErrorChk2(query)
# example usage
inrow = {'eqmtvs_id': eqmtvsid, 'datetime': dtime, 'param_id': paramid}
self.sql_replace(tableobject=db.RT_eqmtvsdata, dictargs=inrow)
Method 6
In case you need to apply an or condition if a condition is met filters can be stored in variable and chained them with a pipe. Here is an example
class Student(db.Model):
__tablename__ = "student"
id = Column(Integer, primary_key=True)
name = Column(String, nullable=False)
def get_by_name(self, name):
condition = # Code Here for condition
filters = (Student.name == "Stack") | (Student.name == "Overflow") if
condition else (Student.name == "Stack")
query = Student.query.filter(filters).order_by(Student.id.asc())
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0