Заказ и разбивка на страницы в SQL-алхимии с использованием не-sql-ранжирования

У меня есть алгоритм python, который возвращает упорядочение рядов строк базы данных для данного пользователя. Этот алгоритм выводит список идентификаторов первичного ключа (эти ключи могут быть соединены с post.id). Он выглядит следующим образом, за исключением того, что есть потенциально тысячи совпадений:

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

Я хочу указать sqlalchemy для выбора этих строк и заказать их по мере их упорядочения в списке. Уловкой является то, что я хотел бы выполнить pagination на этом

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)

Я использую Postgresql в качестве базы данных.

Ответы

Ответ 1

Если есть хорошее решение, я собираюсь взломать свой собственный объект paginate:

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

Я думаю, что единственный способ сделать заказ - создать список всех результатов и отсортировать его в 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

Ответ 2

Я думаю, что упорядочение важнее, потому что без него разбиение на страницы базы данных совершенно бесполезно. Отметив это, мой ответ вообще не касается аспекта разбиения на страницы, но я предполагаю, что для этого можно использовать даже ответ, предоставленный @mgoldwasser.

Это то, что я придумал, чтобы иметь возможность выбирать некоторые объекты и сохранять их порядок в соответствии с первоначальным списком фильтров. Код сам по себе поясняет:

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