2014-07-03 8 views
14

Ich habe einen Python-Algorithmus, der eine Rangordnung der Datenbankzeilen für einen bestimmten Benutzer zurückgibt. Dieser Algorithmus gibt eine Liste von Primärschlüssel-IDs aus (diese Schlüssel könnten mit post.id verbunden werden). Es sieht aus wie die unten, mit der Ausnahme, dass es potenziell Tausende von Begegnungen:Bestellung und Seitenumbruch in SQL-Alchemie mit nicht-SQL-Ranking

result_rank = [1286, 1956, 6759, 3485, 2309, 3409, 9023, 912, 13098, 23489, 19023, 1239] 

Ich mag sqlalchemy anweisen, diese Zeilen zu wählen, und um sie, wie sie in der Liste geordnet. Der Haken ist, dass ich pagination auf dieser

results = posts.query().filter(posts.id.in_(
    resultIds)).order_by(??? how can I order by post.id = result_rank ???).paginate(page_num, posts_per_page) 

ausführen möchte ich Postgresql als Datenbank benutze.

+0

Ich habe genau das gleiche Problem. – anvd

+0

Welches Datenbank-Backend verwenden Sie? – van

+1

@van in meinem Fall ist Postgres. Ich weiß nicht über mgoldwasser – anvd

Antwort

1

Es sei denn, eine gute Lösung ist, werde ich zusammen Objekt mein eigenes Paginieren hacken:

class paginate_obj: 

    """ Pagination dummy object. Takes a list and paginates it similar to sqlalchemy paginate() """ 
    def __init__(self, paginatable, page, per_page): 
     self.has_next = (len(paginatable)/per_page) > page 
     self.has_prev = bool(page - 1) 
     self.next = page + self.has_next 
     self.prev = page - self.has_prev 
     self.items = paginatable[(page-1)*(per_page):(page)*(per_page)] 

ich die einzige Art und Weise denken Bestellung zu tun ist, um eine Liste aller Ergebnisse zu erstellen und sortieren sie in python nach einiger Lambda-Funktion:

results = my_table.query().all() 
results.sort(key=lamba x: distance(x.lat, x.long, user_lat, user_long) 
paginated_results = paginate_obj(results, 1, 10) #returns the first page of 10 elements 
1

denke ich, dass die Anordnung wichtiger ist, weil ohne sie die Datenbankebene Paginierung völlig nutzlos ist. Nachdem ich es zur Kenntnis genommen habe, bezieht sich meine Antwort nicht auf den Paginierungsaspekt, aber ich nehme an, dass sogar die Antwort von @mgoldwasser dafür verwendet werden kann.

Dies ist, was ich gefunden habe, um in der Lage zu sein, einige Objekte auszuwählen und die Reihenfolge von ihnen gemäß der anfänglichen Filterliste beizubehalten. Der Code ist selbsterklärend:

# input 
post_ids = [3, 4, 1] 

# create helper (temporary in-query table with two columns: post_id, sort_order) 
# this table looks like this: 
# key | sort_order 
# 3 |   0 
# 4 |   1 
# 1 |   2 
q_subq = "\nUNION ALL\n".join(
    "SELECT {} AS key, {} AS sort_order".format(_id, i) 
    for i, _id in enumerate(post_ids) 
) 

# wrap it in a `Selectable` so that we can use JOINs 
s = (select([literal_column("key", Integer), 
      literal_column("sort_order", Integer)]) 
    .select_from(text("({}) AS helper".format(text(q_subq)))) 
    ).alias("helper") 

# actual query which is both the filter and sorter 
q = (session.query(Post) 
    .join(s, Post.id == s.c.key) # INNER JOIN will filter implicitly 
    .order_by(s.c.sort_order) # apply sort order 
    ) 

Es beide Werke auf postgresql und sqlite.

+0

Ich denke, der einfachste Weg besteht darin, den context_processor zu verwenden, Unterlisten zu erstellen, die durch die gesamte Seitenzahl dividiert werden, und für jedes Element in der Liste eine spezifische Abfrage filter_by = X auszuführen. Das Problem ist das Seitenumbruch-Widget, aber dies kann manuell erfolgen. Teilen Sie die gesamten Elemente der Liste durch die Seitensumme. Wie auch immer, ich werde warten, um zu überprüfen, ob da ein Freund freundlich ist. – anvd