2011-10-30 12 views
119

He buscado through the docs y no puedo encontrar la forma de hacer una consulta O en SQLAlchemy. Solo quiero hacer esta consulta.Usando O en SQLAlchemy

SELECT address FROM addressbook WHERE city='boston' AND (lastname='bulger' OR firstname='whitey') 

debe ser algo como

addr = session.query(AddressBook).filter(City == "boston").filter(????) 

Respuesta

200

Desde el tutorial:

from sqlalchemy import or_ 
filter(or_(User.name == 'ed', User.name == 'wendy')) 
+48

Tenga en cuenta que este enfoque es compatible con generadores que utilizan, por lo que si usted tiene una larga lista de cosas a O, que puede hacer 'filtro (or_ (v == User.name para v in ('Alice', 'Bob', 'Carl'))) ' – robru

+20

@ El consejo de Robru es innecesariamente ineficiente. Si ya tiene una colección, debe usar el operador 'in_' como este:' filter (User.name.in _ (['Alice', 'Bob', 'Carl'])) ' – intgr

+2

Ah, gracias, no estaba al tanto sqlalchemy tenía ese filtro – robru

229

SQLAlchemy sobrecarga los operadores de bits &, | y ~ lo que en lugar de lo feo y difícil de leer sintaxis de prefijo con or_() y and_() (como en Bastien's answer) puede utilizar estos operadores:

.filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey')) 

Tenga en cuenta que los paréntesis son opcionales no debido a la precedencia de los operadores bit a bit.

Por lo que su consulta completa podría tener este aspecto:

addr = session.query(AddressBook) \ 
    .filter(AddressBook.city == "boston") \ 
    .filter((AddressBook.lastname == 'bulger') | (AddressBook.firstname == 'whitey')) 
+8

+1, pero ¿podría envolver los dos últimos argumentos de filtro en más paréntesis y usar un '&' entre ellos y el primero (en lugar de usar una segunda llamada de 'filtro') para obtener el mismo efecto? –

+13

@ChaseSandmann: Sí, podrías. ¿Pero sería más legible? No. – ThiefMaster

17

operador or_ puede ser útil en caso de número desconocido de O componentes de consulta.

Por ejemplo, supongamos que estamos creando un servicio REST con algunos filtros opcionales, que debería devolver el registro si alguno de los filtros devuelve verdadero. Por otro lado, si el parámetro no se definió en una solicitud, nuestra consulta no debería cambiar. Sin or_ función tenemos que hacer algo como esto:

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)) 

Con or_ función puede ser reescrita para:

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)) 
3

Esto ha sido de gran ayuda. Aquí es mi aplicación para cualquier tabla dada:

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) 
+0

Lo siento, cometí un pequeño error, chanhe siguiendo la línea: query = select ([tableobject]). Where (y _ (* filterargs)) – delpozov

Cuestiones relacionadas