2010-12-05 16 views
6

Gibt es eine Möglichkeit, die vorherigen/nächsten Datensätze aus einer SqlAlchemy-Abfrage zu erhalten? Wie so:SqlAlchemy prev/next accessors?

record.id 
record.next.id 
record.prev.id 

konnte ich die prev/next Methoden zu jedem Modell hinzufügen mich, aber ich frage mich, ob es bereits einige automagischen Weise, die ich übersehen. Die betreffende Webanwendung ist in Pylonen geschrieben.

Bearbeiten: Dies ist wahrscheinlich ein schmutziger Hack, aber es funktioniert. Ich importierte das sqlalchemy Session-Objekt in mein Modell und tat dies:

def next(self): 
    return Session.query(Blog).filter(Blog.id > self.id).order_by(Blog.id).first() 

def prev(self): 
    return Session.query(Blog).filter(Blog.id < self.id).order_by(desc(Blog.id)).first() 
+0

Ohne das Modell zu ändern (indem Sie die Beziehung zu den Tabellen hinzufügen), ist Ihre Lösung ziemlich gut. Das einzige, was ich ändern würde, ist die 'Session.query (...' zu 'Session.object_session (self) .query (...' (siehe http://www.sqlalchemy.org/docs/orm/session). html # sqlalchemy.orm.session.Session.object_session) – van

+0

Um dies klarzustellen, verwendet Session.query die globale Session-Klasse, die in Ihrem eigenen Projekt definiert ist, und Session.object_session verwendet die Session-Klasse, die mit sqlalchemy geliefert wird. –

Antwort

-2

Was würde ich vorschlagen, in Ihrer ursprünglichen Abfrage tut, ist anfordernden -1 und +1, so dass Sie leicht die IDs erhalten, ohne eine weitere Abfrage auszuführen, die Sparen Sie Zeit bei der Verarbeitung auf dem SQL-Server.

Ihre Lösung funktioniert definitiv, erfordert jedoch zwei zusätzliche Abfragen. Sie könnten es sogar zu einer Unterabfrage machen, so dass, wenn Sie nur eine einzelne Zeile abrufen und vorherige/nächste darauf werfen möchten, dass Daten in einer Spalte gespeichert werden, die durch eine Unterabfrage erstellt wurde.

+0

min one und plus one wird nicht funktionieren, wenn Sie einige Datensätze in der Zwischenzeit löschen. Weil mysql (database) eine eigene ID hat und nicht plus eins oder minus eins. Es scheint, dass es jetzt einen Weg dazu gibt. – pregmatch

0

Plus 1 und Minus 1 im letzten Datenbankeintrag funktionieren manchmal. Was passiert, wenn Sie einige der letzten Datensätze löschen? Nächste ID wird nicht plus eins oder minus eins in der letzten ID sein. Das ist keine Session-Sache, es ist Mysql-Sache. Um die nächste ID zu erhalten, müssen Sie einige Fragen zu einem solchen Informationsschema stellen.

q = "SELECT auto_increment FROM INFORMATION_SCHEMA.TABLES WHERE table_name='table_name'" 
a = s.execute(q) #where s is sqlalchemy session 

for b in a: 

    print b 
    print b[0] 

, dass Sie so etwas wie geben: (163459L,) 163459

In meinem Fall ist das wahr.

Und für die prev können Sie immer .first() auf Ihrem letzten Datensatz. Das ist prev record.

0

Hier ist, was ich benutze, um nächste/vorherige aus einem Objekt mithilfe von sqlalchemy abrufen. Die Idee ist es, die row_number des Objekts aus der ersten Liste und machen eine weitere Anforderung mit einem Offset +/- 1.

Ich bin mit einer Unterabfrage mit ROW_NUMBER (How do I use ROW_NUMBER()?) bekommen die row_number von der ersten Abfrage abzurufen:

row_number = func.row_number().over(order_by=orders).label("row_number") 
row_number_subquery = self.getlistquery(columns=chain([row_number], pk_columns)).subquery() 

Dann schließe ich mich mit dem Modell auf Primärschlüsseln:

join_clause = [getattr(row_number_query.c, pk.key) == getattr(model, pk.key) for pk in pk_columns] 

I von dem Primärschlüssel des Objektfilter:

012.
filter = [getattr(model, pk.key) == pk_values[index] for index, pk in enumerate(pk_columns)] 

I erstellen die endgültige Abfrage der Offset des Objekt zu erhalten:

offset = db.session.query(row_number_subquery).join(model, *join_clause).filter(*filter).first() 

dann das Element die für das nächste oder offset-2 für frühere benötigt offset enthält (wie in 1 für row_number beginnend und 0 für Offset)

self.getlistquery().offset(offset)