在 Django 模型查询中按顺序排列的原始 SQL

Posted

技术标签:

【中文标题】在 Django 模型查询中按顺序排列的原始 SQL【英文标题】:Raw SQL in order by in django model query 【发布时间】:2021-10-01 20:22:54 【问题描述】:

我有一个这样的简单查询(我希望先出现 1 BHK,然后是 2BHK,然后是其他任何东西

select *
from service_options
order by case space when '1BHK' then 0 when '2BHK' then 1 else 2 end,
         space

在 Django 中,怎么做?我有一个模型名为ServiceOption

我试过了,但没有运气。

ServiceOption.objects.order_by(RawSQL("case space when '1BHK' then 0 when '2BHK' then 1 else 2 end,space"), ()).all()

我不想使用类似的东西执行原始查询

ServiceOption.objects.raw("raw query here")

Laravel 中,这样的事情可以很容易地像这样实现

Model::query()->orderByRaw('raw order by query here')->get();

我们将不胜感激。提前谢谢你。

【问题讨论】:

【参考方案1】:

您可以使用.annotate(…) [Django-doc],然后使用.order_by(…) [Django-doc]:

from django.db.models import Case, IntegerField, Value, When

ServiceOption.objects.annotate(
    sp=Case(
        When(space='1BHK', then=Value(0)),
        When(space='2BHK', then=Value(1)),
        default=Value(2),
        output_field=IntegerField()
    )
).order_by('sp', 'space')

原始查询会到这里

SELECT *, CASE WHEN "service_options"."space" = 1BHK THEN 0 WHEN "service_options"."space" = 2BHK THEN 1 ELSE 2 END AS "sp" FROM "service_options" ORDER BY "sp" ASC, "service_options"."space" ASC

由于django-3.2,您可以使用.alias(…) [Django-doc] 来防止将其计算为列和ORDER BY 子句:

from django.db.models import Case, IntegerField, Value, When

ServiceOption.objects.alias(
    sp=Case(
        When(space='1BHK', then=Value(0)),
        When(space='2BHK', then=Value(1)),
        default=Value(2),
        output_field=IntegerField()
    )
).order_by('sp', 'space')

原始查询会到这里

SELECT * FROM "service_options" ORDER BY CASE WHEN ("service_options"."space" = 1BHK) THEN 0 WHEN ("service_options"."space" = 2BHK) THEN 1 ELSE 2 END ASC, "service_options"."space" ASC

【讨论】:

您好,感谢您的解决方案。但是,有没有办法只为 order by 执行原始查询?在 laravel 中,我可以使用 $query->orderByRaw('raw order by query here') 之类的方法轻松完成。 为您的答案执行的实际查询将转换为 select *, case space when '1BHK' then 0 when '2BHK' then 1 else 2 end as sp from service_options order by sp, space 但是,这与我在问题中建议的原始查询完全不同。 @KoushikDas: 不,如果您使用.annotate 执行此操作,那么它将在SELECTORDER BY 子句中使用sp,如果您使用.alias(...)它只会在必要的地方使用ORDER BY 中的CASE ...

以上是关于在 Django 模型查询中按顺序排列的原始 SQL的主要内容,如果未能解决你的问题,请参考以下文章

在django模板中按id的顺序显示查询集及其外键

尝试使用 django 从 postgres DB 中按顺序获取下一个值

NestJS 在 SwaggerUI 中按字母顺序排列端点

dplyr:在 R 中按字母顺序排列列

PHP 在Wordpress中按字母顺序排列的相邻帖子

在 UITableView 中按时间顺序排列 Firebase 帖子(最新的优先)