我想使用Postgresql的「NULLS LAST」選項對模型進行排序。 怎麼辦?Django:將「NULLS LAST」添加到查詢
我想是這樣
MyModel.objects.all().extra(order_by=('-price', 'NULLS LAST'))
,但我得到
「無法解析關鍵字‘空值LAST’到現場」
我發現我想使用Postgresql的「NULLS LAST」選項對模型進行排序。 怎麼辦?Django:將「NULLS LAST」添加到查詢
我想是這樣
MyModel.objects.all().extra(order_by=('-price', 'NULLS LAST'))
,但我得到
「無法解析關鍵字‘空值LAST’到現場」
我發現最近的事情是做什麼的兩腳步。所填充的字段,然後在空第一順序:
通過this要點(本身通過這些django logs):
all_projects = Project.objects.select_related().filter(
company=company).order_by('-date_due')
q = all_projects.extra(select={'date_due_null': 'date_due is null'})
q = q.extra(order_by=['date_due_null'])
print q.query
好運。
如果你希望它是透明的完成和所有列,您可以重新定義SQL生成。爲此,您需要讓自己的Manager返回您的自定義QuerySet,以返回您的自定義Query以使用自定義Compiler。我的代碼看起來像這樣(Django的1.5):
from django.db import models, connections
class NullsLastQuery(models.sql.query.Query):
"""
Query that uses custom compiler,
to utilize PostgreSQL feature of setting position of NULL records
"""
def get_compiler(self, using=None, connection=None):
if using is None and connection is None:
raise ValueError("Need either using or connection")
if using:
connection = connections[using]
# defining that class elsewhere results in import errors
from django.db.models.sql.compiler import SQLCompiler
class NullsLastSQLCompiler(SQLCompiler):
def get_ordering(self):
result, group_by = super(NullsLastSQLCompiler, self
).get_ordering()
if self.connection.vendor == 'postgresql' and result:
result = [line + " NULLS LAST" for line in result]
return result, group_by
return NullsLastSQLCompiler(self, connection, using)
class NullsLastQuerySet(models.query.QuerySet):
def __init__(self, model=None, query=None, using=None):
super(NullsLastQuerySet, self).__init__(model, query, using)
self.query = query or NullsLastQuery(self.model)
class NullsLastManager(models.Manager):
def get_query_set(self):
return NullsLastQuerySet(self.model, using=self._db)
class YourModel(models.Model):
objects = NullsLastManager()
這有點邪惡,但很精彩。 – 2013-09-23 15:12:42
Django的1.9(也可能是1.8),您可以使用此:
from django.db import connections, models
from django.db.models.sql.compiler import SQLCompiler
class NullsLastSQLCompiler(SQLCompiler):
def get_order_by(self):
result = super().get_order_by()
if result and self.connection.vendor == 'postgresql':
return [(expr, (sql + ' NULLS LAST', params, is_ref))
for (expr, (sql, params, is_ref)) in result]
return result
class NullsLastQuery(models.sql.query.Query):
"""Use a custom compiler to inject 'NULLS LAST' (for PostgreSQL)."""
def get_compiler(self, using=None, connection=None):
if using is None and connection is None:
raise ValueError("Need either using or connection")
if using:
connection = connections[using]
return NullsLastSQLCompiler(self, connection, using)
class NullsLastQuerySet(models.QuerySet):
def __init__(self, model=None, query=None, using=None, hints=None):
super().__init__(model, query, using, hints)
self.query = query or NullsLastQuery(self.model)
,然後在你的模型(S):
objects = NullsLastQuerySet.as_manager()
這是基於從蒂姆https://stackoverflow.com/a/17077587/15690答案。
爲它添加支持Django的車票已經重開:https://code.djangoproject.com/ticket/13312。
這可能是不可用的時候有人問,但因爲Django的1.8,我認爲這是最好的解決辦法:
from django.db.models.functions import Coalesce, Value
MyModel.objects.all().annotate(price_null=
Coalesce('price', Value(-100000000)).order_by('-price_null')
Coalesce
選擇的第一個非空值,讓你創造一個價值price_null
到順序是隻是價格,但用null
取代-100000000
(或+
?)。
這實際上是一個很好的破解,因爲它不需要創建NULLS LAST索引和類似的東西來加速查詢 – valignatev 2016-10-27 12:37:17
@valentjedi這不是需要一個表達式索引'Coalesce('price',Value(-100000000)'?這與創建一個NULLS LAST索引是一樣的。這裏http://dba.stackexchange.com/a/99009有人聲明相同我的意思是 – jperelli 2016-12-09 14:56:13
@ jperelli實際上你是對的,但在我的情況下,這種破解比添加NULLS LAST快,所以它讓我滿意。 – valignatev 2016-12-09 19:20:04
此功能已添加到Django 1.11(至寫入仍處於測試階段)。
https://docs.djangoproject.com/en/dev/releases/1.11/
添加了nulls_first和nulls_last參數Expression.asc() 和desc()來控制空值的排序。
感謝。這確實不是完美的解決方案,但有點作品 – GabiMe 2013-02-28 20:44:08
不客氣。我認爲沒有一個完美的解決方案,或者至少有一個由Django直接設想的[谷歌組織發佈](https://groups.google.com/d/msg/django-users/sxbpqmkRyCU/ qUYjX3niCOEJ)由馬爾科姆Treddinick。 – Mariano 2013-02-28 22:07:00