web-dev-qa-db-fra.com

Application de LIMIT et OFFSET à toutes les requêtes dans SQLAlchemy

Je conçois une API avec SQLAlchemy (interroger MySQL) et j'aimerais forcer toutes mes requêtes à avoir les paramètres page_size (LIMIT) et page_number (OFFSET).

Y a-t-il un moyen propre de faire cela avec SQLAlchemy? Peut-être construire une usine pour créer un objet Query personnalisé? Ou peut-être y a-t-il un bon moyen de faire cela avec un cours de mixage?

J'ai essayé la solution évidente et cela n'a pas fonctionné car .limit () et .offset () doivent être appelés après l'application de toutes les conditions de filtrage:

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'essaye d'utiliser ceci, j'obtiens 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.
32
Rob Crowell

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
32
pydsigner

Pas une option au moment de cette question, depuis la version 1.0.0, vous pouvez tirer parti de Evénements de requête pour vous assurer que les méthodes limit et offset sont toujours appelées juste avant la compilation de votre objet query, après toute manipulation effectuée par le utilisateurs de votre fonction q:

from sqlalchemy.event import listen


def q(page=0, page_size=None):
    query = session.query()
    listen(query, 'before_compile', apply_limit(page, page_size), retval=True)
    return query

def apply_limit(page, page_size):
    def wrapped(query):
        if page_size:
            query = query.limit(page_size)
            if page:
                query = query.offset(page * page_size)
        return query
    return wrapped
0
Daniele