Python 使用非SQL排序的SQL炼金术中的排序和分页

Python 使用非SQL排序的SQL炼金术中的排序和分页,python,flask,pagination,sqlalchemy,flask-sqlalchemy,Python,Flask,Pagination,Sqlalchemy,Flask Sqlalchemy,我有一个python算法,它返回给定用户的数据库行的排序。该算法输出主键id列表(这些键可以与post.id连接)。除了可能有数千个匹配项外,它看起来如下所示: result_rank = [1286, 1956, 6759, 3485, 2309, 3409, 9023, 912, 13098, 23489, 19023, 1239] 我想指示sqlalchemy选择这些行,并按照它们在列表中的顺序对它们进行排序。问题是我想在这上面表演 我使用Postgresql作为数据库 除非有一个好的解

我有一个python算法,它返回给定用户的数据库行的排序。该算法输出主键id列表(这些键可以与post.id连接)。除了可能有数千个匹配项外,它看起来如下所示:

result_rank = [1286, 1956, 6759, 3485, 2309, 3409, 9023, 912, 13098, 23489, 19023, 1239]
我想指示sqlalchemy选择这些行,并按照它们在列表中的顺序对它们进行排序。问题是我想在这上面表演


我使用Postgresql作为数据库

除非有一个好的解决方案,否则我将整理我自己的分页对象:

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)]
我认为进行排序的唯一方法是创建一个所有结果的列表,并根据lambda函数在python中对其进行排序:

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

我认为排序更重要,因为没有它,数据库级分页就完全没有用处。注意到这一点,我的答案根本不包括分页方面,但我假设即使@mgoldwaser提供的答案也可以用于此

这就是我所想到的,以便能够选择一些对象,并按照初始过滤器列表保留它们的顺序。代码是不言自明的:

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

它在
postgresql
sqlite

上都有效。我遇到了完全相同的问题。您使用哪个数据库后端?我的例子中的@van是postgres。我不知道MGoldwaser有两个问题:(1)给定用户的帖子排名多久会改变一次?(2)你的排名算法需要读取数据库中的所有帖子吗,或者不这样做它能工作吗?@Miguel作为《赏金》的作者,我会相应地回答我的情况。我考虑的是一个实时排名,所以每次用户看到页面时,排名都会被处理。每个帖子都有一个分数,与其他帖子相关。所以,是的,我需要处理所有的帖子。你对我在下面帖子中的评论有什么看法?我认为最简单的方法就是使用上下文处理器,创建子列表除以总页数,然后为列表中的每个元素运行一个特定的查询过滤器。\u by=X。问题是分页小部件,但这可以手动完成。只需将列表中的所有元素除以页面总数即可。无论如何,我将等待检查是否有这样做的方法。
# 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
     )