我想使用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