2010-04-20 12 views

Respuesta

15

Suponiendo que la variable de terms contiene fragmentos de sentencias SQL válidos, puede simplemente pasar terms precedido por un asterisco a or_ o and_:

>>> from sqlalchemy.sql import and_, or_ 
>>> terms = ["name='spam'", "email='[email protected]'"] 
>>> print or_(*terms) 
name='spam' OR email='[email protected]' 
>>> print and_(*terms) 
name='spam' AND email='[email protected]' 

Tenga en cuenta que esto supone que terms incluye solamente válida y escapó correctamente fragmentos SQL, por lo que esto es potencialmente inseguro si un usuario malintencionado puede acceder terms someh Ay.

En lugar de crear fragmentos de SQL usted mismo, debe dejar que SQLAlchemy cree consultas SQL parametrizadas utilizando otros métodos desde sqlalchemy.sql. No sé si ha preparado objetos Table para sus tablas o no; si es así, suponga que tiene una variable llamada users que es una instancia de Table y describe su tabla users en la base de datos. A continuación, puede hacer lo siguiente:

from sqlalchemy.sql import select, or_, and_ 
terms = [users.c.name == 'spam', users.c.email == '[email protected]'] 
query = select([users], and_(*terms)) 
for row in conn.execute(query): 
    # do whatever you want here 

Aquí, users.c.name == 'spam' creará un objeto sqlalchemy.sql.expression._BinaryExpression que registra que esta es una relación de igualdad binaria entre la columna de la tabla de nameusers y una cadena literal que contiene spam. Cuando convierte este objeto en una cadena, obtendrá un fragmento de SQL como users.name = :1, donde :1 es un marcador de posición para el parámetro. El objeto _BinaryExpression también recuerda el enlace de :1 al 'spam', pero no lo insertará hasta que se ejecute la consulta SQL. Cuando se inserta, el motor de base de datos se asegurará de que se haya escapado correctamente. Lectura recomendada: SQLAlchemy's operator paradigm

Si sólo tiene la tabla de base de datos, pero usted no tiene una variable users que describe la tabla, puede crear usted mismo:

from sqlalchemy import Table, MetaData, Column, String, Boolean 
metadata = MetaData() 
users = Table('users', metadata, 
    Column('id', Integer, primary_key=True), 
    Column('name', String), 
    Column('email', String), 
    Column('active', Integer) 
) 

Como alternativa, puede utilizar la auto-carga que consulta el motor de base de datos para la estructura de la base de datos y compila users automáticamente; Obviamente esto es más lento:

users = Table('users', metadata, autoload=True) 
+0

¿Alguna sugerencia sobre dónde buscar para descubrir cómo puedo crear "fragmentos SQL válidos y escapados correctamente" de una lista de cadenas? –

+0

He buscado en la documentación de SQLAlchemy por un tiempo, pero parece que esta no es la forma correcta de hacerlo con SQLAlchemy. En lugar de crear fragmentos de SQL usted mismo, debe dejar que SQLAlchemy genere consultas SQL parametrizadas usando otros métodos de 'sqlalchemy.sql'. Extenderé mi respuesta en breve para proporcionar más detalles. –

21

Si usted tiene una lista de términos y quiere encontrar filas en las que un campo coincide con uno de ellos, entonces se podría utilizar el método in_():

terms = ['term1', 'term2', 'term3'] 
query.filter(Cls.field.in_(terms)) 

Si desea hacer algo más complejo, entonces or_() y and_() toman ClauseElement objetos como parámetros. ClauseElement y sus subclases representan básicamente el SQL AST de su consulta.Normalmente se crea elementos cláusula mediante la invocación de un operador de comparación en la columna o InstrumentedAttribute objetos:

# Create the clause element 
clause = (users_table.columns['name'] == "something") 
# you can also use the shorthand users_table.c.name 

# The clause is a binary expression ... 
print(type(clause)) 
# <class 'sqlalchemy.sql.expression._BinaryExpression'> 
# ... that compares a column for equality with a bound value. 
print(type(clause.left), clause.operator, type(clause.right)) 
# <class 'sqlalchemy.schema.Column'>, <built-in function eq>, 
# <class 'sqlalchemy.sql.expression._BindParamClause'> 

# str() compiles it to SQL 
print(str(clause)) 
# users.name = ? 

# You can also do that with ORM attributes 
clause = (User.name == "something") 
print(str(clause)) 
# users.name = ? 

Puede manejar elementos cláusula que representan sus condiciones como cualquier objeto de Python, ponerlos en listas, componerlos en otros elementos cláusula, etc. así que usted puede hacer algo como esto:

# Collect the separate conditions to a list 
conditions = [] 
for term in terms: 
    conditions.append(User.name == term) 

# Combine them with or to a BooleanClauseList 
condition = or_(*conditions) 

# Can now use the clause element as a predicate in queries 
query = query.filter(condition) 
# or to view the SQL fragment 
print(str(condition)) 
# users.name = ? OR users.name = ? OR users.name = ? 
Cuestiones relacionadas