2012-11-06 5 views
25

Je concevais une API avec SQLAlchemy (interrogeant MySQL) et je voudrais forcer toutes mes requêtes à avoir les paramètres page_size (LIMIT) et page_number (OFFSET).Application de LIMIT et OFFSET à toutes les requêtes dans SQLAlchemy

Existe-t-il une manière propre de faire cela avec SQLAlchemy? Peut-être construire une usine de quelque sorte pour créer un objet de requête personnalisé? Ou peut-être y a-t-il un bon moyen de le faire avec un cours de mixin?

J'ai essayé la chose évidente et il ne fonctionne pas parce que .limit() et .Offset() doit être appelée après toutes les conditions de filtrage ont été appliquées:

def q(page=0, page_size=None): 
    q = session.query(...) 
    if page_size: q = q.limit(page_size) 
    if page: q = q.offset(page*page_size) 
    return q 

Quand j'essayer d'utiliser cela, je obtenir l'exception:

sqlalchemy.exc.InvalidRequestError: Query.filter() being called on a Query which already has LIMIT or OFFSET applied. To modify the row-limited results of a Query, call from_self() first. Otherwise, call filter() before limit() or offset() are applied. 
+0

S'il vous plaît ne pas modifier une solution dans votre question. Au lieu de cela, affichez-le comme une réponse distincte ci-dessous. – Matt

Répondre

25

Essayez d'ajouter un premier argument requis, qui doit être un groupe de filtres de requête. Ainsi,

# q({'id': 5}, 2, 50) 
def q(filters, page=0, page_size=None): 
    query = session.query(...).filter_by(**filters) 
    if page_size: 
     query = query.limit(page_size) 
    if page: 
     query = query.offset(page*page_size) 
    return query 

ou,

# q(Model.id == 5, 2, 50) 
def q(filter, page=0, page_size=None): 
    query = session.query(...).filter(filter) 
    if page_size: 
     query = query.limit(page_size) 
    if page: 
     query = query.offset(page*page_size) 
    return query 
+1

En le décomposant en 2 parties (obtenez l'objet Query, appliquez des filtres obligatoires), nous comptons sur le développeur pour nous rappeler d'appeler q() sur toutes ses requêtes. Les résultats seront toujours générés si quelqu'un oublie d'appeler q() avant d'appeler tout(). –

+0

Ensuite, vous devez prendre, plutôt qu'une requête, un dictionnaire de filtre. Mais cela vous limitera un peu. – pydsigner

+1

@RobCrowell Trois ans plus tard, je suis curieux de savoir si cela a résolu votre problème ou si vous avez fini par faire quelque chose d'autre (auquel cas ce serait bien de vous voir répondre sur ce que vous avez trouvé)? – pydsigner

Questions connexes