LoginSignup
0
1

More than 5 years have passed since last update.

djangoのQuerySetでorder_byした時、Noneを最後に持っていきたい

Last updated at Posted at 2017-11-13

経緯

一度DjangoQuerySet内で取得した要素をしっかりオーダーできたら便利だ。
だが、テーブルのpriorityカラムはNULL値も受け入れていて、普通にorder_by('priority')とかやってしまうと、NULLのものが一番先頭に来てしまう。一方で、仕様ではpriority=Noneは劣後ということになっている。
したがって、今までは、DQSで取得した後でsorted+lambdaを使って整列していた。

これを、やはりDQSで一気に実現してしまいたい…。

解決法

DQSでextraを使う。
extraのselectを使うと、selectの結果を新しく命名した内容であたり外れ判定してくれる

# example
target_features = list(MFeature.objects.using('front')
                                               .select_related()
                                               .filter(is_active=Common.IS_ACTIVE_ON,
                                                       end_dt__gte=now,
                                                       start_dt__lte=now,
                                                       mfeaturetalent__is_active=Common.IS_ACTIVE_ON,
                                                       mfeaturetalent__talent__is_active=Common.IS_ACTIVE_ON)
                                               .values('id', 'title', 'detail', 'link_url', 'priority', 'start_dt',
                                                       'mfeaturetalent__title', 'mfeaturetalent__footnote',
                                                       'mfeaturetalent__link_url', 'mfeaturetalent__image_url',
                                                       'mfeaturetalent__talent__id', 'mfeaturetalent__talent__name',
                                                       'mfeaturetalent__talent__photo_ext', 'mfeaturetalent__rank')
                                               .extra(select={'priority_is_null': "m_feature.priority IS NULL"})
                                               .order_by('priority_is_null', 'priority', '-start_dt', 'mfeaturetalent__rank'))

ここではextraでpriority_is_nullという定義名にm_feature.priority IS NULLの判定が入る。そこで、それをorder_byの中に渡してやると、priorityのNULL判定が機能する。

注意点

extra(select={})の中で、m_feature.priorityとせずに、priorityとだけにすると、Django column 'priority' in order clause is ambiguousというmysqlの警告が出る。
これは、上記のDQLでm_feature_talentをinner joinしているため、どのテーブルのpriorityかが明確じゃないことから起こるエラー。

参考URL

Django Order By Date, but have “None” at end?
QuerySet API リファレンス#extra

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1