diff --git a/ox/django/query.py b/ox/django/query.py new file mode 100644 index 0000000..22f6b96 --- /dev/null +++ b/ox/django/query.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 + +from django.db.models.query import QuerySet +from django.db.models.sql import Query +from django.db.models.sql.compiler import SQLCompiler +from django.db import connections + +''' +models.py: +----------------------------------- +from ox.django.query import QuerySet + +class Manager(models.Manager): + def get_query_set(self): + return QuerySet(self.model) + +class Model(models.Model): + ... + objects = Manager() +''' + +class SQLCompiler(SQLCompiler): + + def get_ordering(self): + result, group_by = super(SQLCompiler, self).get_ordering() + if self.query.nulls_last and len(result): + result = map(lambda e: e + ' NULLS LAST', result) + return result, group_by + +class Query(Query): + nulls_last = False + + def clone(self, *args, **kwargs): + obj = super(Query, self).clone(*args, **kwargs) + obj.nulls_last = self.nulls_last + return obj + + 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] + # Check that the compiler will be able to execute the query + for alias, aggregate in self.aggregate_select.items(): + connection.ops.check_aggregate_support(aggregate) + + return SQLCompiler(self, connection, using) + + +class QuerySet(QuerySet): + + def __init__(self, model=None, query=None, using=None): + super(QuerySet, self).__init__(model=model, query=query, using=None) + self.query = query or Query(self.model) + + def order_by(self, *args, **kwargs): + nulls_last = kwargs.pop('nulls_last', False) + obj = super(QuerySet, self).order_by(*args, **kwargs) + obj.query.nulls_last = nulls_last + return obj