Sqlalchemy按列表中的字段过滤但保留原始订单?

时间:2015-03-29 06:26:58

标签: python sqlalchemy flask-sqlalchemy

我有一个像这样的鞋子模型:

class Shoe(db.Model):
id = db.Column(db.Integer, primary_key = True)
asin = db.Column(db.String(20), index = True)

我有一个id列表,如ids = [2,1,3],当我查询Shoe模型,结果在'ids'列表中有id时,我想要回复: [{id:2,asin:“111”},{id:1,asin:“113”},{id:3,asin:“42”}]但问题是使用以下查询语句不会保留原始顺序,结果将随机返回。如何保持我过滤的列表顺序?

不正确的一个:Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()

4 个答案:

答案 0 :(得分:11)

如果你有一个合理的小ID列表,你可以单独对每个id执行SQL查询:

[Shoe.query.filter_by(id=id).one() for id in my_list_of_ids]

对于大量ID,SQL查询将花费很长时间。然后,您最好使用单个查询并在第二步中将值放入正确的顺序(从how to select an object from a list of objects by its attribute in python借用):

shoes = Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).all()
[next(s for s in shoes if s.id == id) for id in my_list_of_ids]

这假设id是唯一的(在你的情况下它们应该是这样)。如果存在多个具有相同id的元素,则第一种方法将引发异常。

答案 1 :(得分:7)

我过去解决这个问题的一种方法是使用SQL CASE expression告诉数据库我想要返回的行的顺序。使用您的示例:

from sqlalchemy.sql.expression import case

ordering = case(
    {id: index for index, id in enumerate(my_list_of_ids)},
    value=Shoe.id
 )
Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).order_by(ordering).all()

答案 2 :(得分:0)

使用MySQL数据库也存在同样的问题。这就是我所做的:

my_list = [13,14,5,6,7]
# convert my_list to str
my_list_str = ','.join(map(str, my_list))

这就是我的查询的样子:

checkpoints = (
    db_session.query(Checkpoint)
    .filter(Checkpoint.id.in_(my_list))
    .order_by('FIELD(id, ' + my_list_str + ')')
    .all()
)

FIELD()是MySQL中的本机函数。

编辑:所以你的查询应该是这样的:

my_list_of_ids_str = ','.join(map(str, my_list_of_ids)) 
Shoe.query.filter(Shoe.id.in_(my_list_of_ids)).order_by('FIELD(id, ' + my_list_of_ids_str + ')').all()

干杯

答案 3 :(得分:-2)

当你说"原始订单&#34 ;?时,你的意思是什么?数据库没有"原始订单"。如果您需要订单,则必须添加以下内容:

.order_by(Shoe.id.desc())

如果您没有指定订单,那么您仍然可以从数据库获取订购数据。但在这种情况下,数据库只使用不需要任何不必要的数据操作的顺序。它只是看起来像一个有序的数据,但它不是。