2010-04-20 2 views

Répondre

15

En supposant que votre variable terms contient des fragments valides instruction SQL, vous pouvez tout simplement passer terms précédé d'un astérisque or_ ou 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]' 

Notez que cela suppose que terms ne contient que valide et correctement échappé fragments SQL, il est donc potentiellement dangereux si un utilisateur malveillant peut accéder à terms someh ow Au lieu de créer vous-même des fragments SQL, vous devez autoriser SQLAlchemy à générer des requêtes SQL paramétrées à l'aide d'autres méthodes, à partir de sqlalchemy.sql. Je ne sais pas si vous avez préparé Table objets pour vos tables ou non; Si c'est le cas, supposons que vous avez une variable appelée users qui est une instance de Table et qu'elle décrit votre table users dans la base de données. Ensuite, vous pouvez effectuer les opérations suivantes:

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 

Ici, users.c.name == 'spam' va créer un objet sqlalchemy.sql.expression._BinaryExpression qui enregistre que c'est une relation d'égalité binaire entre la colonne name de la table users et un littéral chaîne qui contient spam. Lorsque vous convertissez cet objet en une chaîne, vous obtiendrez un fragment SQL comme users.name = :1, où :1 est un espace réservé pour le paramètre. L'objet _BinaryExpression se souvient également de la liaison de :1 à 'spam', mais il ne l'insère pas tant que la requête SQL n'est pas exécutée. Quand il est inséré, le moteur de base de données s'assurera qu'il est correctement échappé. Suggestion de lecture: SQLAlchemy's operator paradigm

Si vous avez seulement la table de base de données, mais vous ne disposez pas d'une variable users qui décrit la table, vous pouvez le créer vous-même:

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

Vous pouvez également utiliser l'auto-chargement qui interroge le moteur de base de données pour la structure de la base de données et construit users automatiquement; Cela est évidemment plus chronophage:

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

Des suggestions sur où chercher pour comprendre comment je peux créer des "fragments SQL valides et correctement échappés" à partir d'une liste de chaînes? –

+0

J'ai cherché la documentation SQLAlchemy pendant un moment, mais il semble que ce n'est pas vraiment la bonne façon de le faire avec SQLAlchemy. Au lieu de créer vous-même des fragments SQL, vous devez laisser SQLAlchemy générer des requêtes SQL paramétrées en utilisant d'autres méthodes de 'sqlalchemy.sql'. J'étendrai ma réponse sous peu pour fournir plus de détails. –

21

Si vous avez une liste de termes et que vous voulez trouver les lignes où un champ correspond à l'un d'entre eux, alors vous pouvez utiliser la méthode in_():

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

Si vous voulez faire quelque chose de plus complexe, alors or_() et and_() prennent ClauseElement comme paramètres. ClauseElement et ses sous-classes représentent essentiellement le SQL AST de votre requête.En général, vous créez des éléments de clause en invoquant un opérateur de comparaison sur les objets de colonne ou InstrumentedAttribute:

# 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 = ? 

Vous pouvez gérer des éléments de clause représentant vos conditions comme des objets Python, les mettre dans des listes, ce qui les composent dans d'autres éléments de clause, etc. ainsi, vous pouvez faire quelque chose comme ceci:

# 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 = ? 
Questions connexes