Django QuerySet 按 ID 自定义排序

发布于 2024-09-16 15:23:13 字数 421 浏览 8 评论 0原文

给定一个 ids/pks 列表,我想生成一个按列表中索引排序的对象的 QuerySet

通常我会从以下开始:

pk_list = [5, 9, 2, 14]
queryset = MyModel.objects.filter(pk__in=pk_list)

这当然会返回对象,但是按照模型元排序属性的顺序,并且我希望按照 中的 pk 的顺序获取记录pk_list

最终结果必须是一个 QuerySet 对象(不是列表),因为我希望将有序的 QuerySet 传递给 Django 的 ModelMultipleChoiceField 表单字段。

Given a list of ids/pks, I'd like to generate a QuerySet of objects ordered by the index in the list.

Normally I'd begin with:

pk_list = [5, 9, 2, 14]
queryset = MyModel.objects.filter(pk__in=pk_list)

This of course returns the objects, but in the order of the models meta ordering property, and I wish to get the records in the order of the pks in pk_list.

The end result has to be one QuerySet object (not a list), as I wish to pass the ordered QuerySet to Django's ModelMultipleChoiceField form field.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

别闹i 2024-09-23 15:23:13

没有内置的方法可以做到这一点。

如果您使用的是 MySQL,则可以使用该数据库的 FIELD() 函数在模型上设置自定义排序序列,并按该序列进行排序。这会起作用:

pk_list = [5, 9, 2, 14]
ordering = 'FIELD(`id`, %s)' % ','.join(str(id) for id in pk_list)
queryset = MyModel.objects.filter(pk__in=[pk_list]).extra(
               select={'ordering': ordering}, order_by=('ordering',))

There isn't a built-in way to do this.

If you're using MySQL, you can use that database's FIELD() function to set up a custom ordering sequence on your model, and sort by that. This would work:

pk_list = [5, 9, 2, 14]
ordering = 'FIELD(`id`, %s)' % ','.join(str(id) for id in pk_list)
queryset = MyModel.objects.filter(pk__in=[pk_list]).extra(
               select={'ordering': ordering}, order_by=('ordering',))
倒带 2024-09-23 15:23:13

在 Django 2.2 中,我可以使用以下方法根据订单列表对 QuerySet 进行排序:

pk_list = [4, 23, 10, 9]
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])
new_qs = qs.filter(pk__in=pk_list).order_by(preserved)

In Django 2.2, I was able to order QuerySet based on an order list using following approach:

pk_list = [4, 23, 10, 9]
preserved = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pk_list)])
new_qs = qs.filter(pk__in=pk_list).order_by(preserved)
这个俗人 2024-09-23 15:23:13

我不知道如何使用过滤条件来做到这一点。如果您的数据库将按照 IN 子句的顺序返回行,那么您也许能够将 Django 的 extra 方法与 结合起来ROWNUM 由您​​的数据库提供来实现此目的。

例如:

queryset = MyModel.objects.filter(pk__in=[pk_list]).extra(
       select: {'rownum': 'row_num()'}).order_by('rownum')

其中 row_num() 被假定为返回当前行的行号的数据库函数。 Postgresql 8.4+ 支持 row_num() 但我不知道如何使用与 IN 子句中的值相同的顺序对返回的行进行排序。

我认为更好的方法是子类 ModelMultipleChoiceField 并在渲染时添加自定义排序逻辑。

I do not know of a way to do this using a filter condition. If your database will return the rows in the order of the IN clause then you may be able to combine Django's extra method with the ROWNUM provided by your database to achieve this.

For e.g.:

queryset = MyModel.objects.filter(pk__in=[pk_list]).extra(
       select: {'rownum': 'row_num()'}).order_by('rownum')

Where row_num() is assumed to be a database function that returns the row number of the current row. Postgresql 8.4+ supports row_num() but I do not know how to order the rows returned using the same order as the values in the IN clause.

I think a better way would be to sub class ModelMultipleChoiceField and add custom sorting logic when rendering.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文