Support Django 1.8 complex expressions on aggregate/annotate

fix_request_path_info
slide333333 2016-01-21 13:21:21 +01:00
parent 5c4ee7484e
commit c5d4687bb9
1 changed files with 16 additions and 10 deletions

View File

@ -7,12 +7,12 @@ from __future__ import absolute_import
from collections import defaultdict from collections import defaultdict
import django import django
from django.db.models.query import QuerySet from django.db.models.query import QuerySet, Q
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils import six from django.utils import six
from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
from .query_translate import translate_polymorphic_field_path from .query_translate import translate_polymorphic_field_path, translate_polymorphic_Q_object
# chunk-size: maximum number of objects requested per db-request # chunk-size: maximum number of objects requested per db-request
# by the polymorphic queryset.iterator() implementation; we use the same chunk size as Django # by the polymorphic queryset.iterator() implementation; we use the same chunk size as Django
@ -115,21 +115,27 @@ class PolymorphicQuerySet(QuerySet):
"""for aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args. """for aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args.
Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)""" Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)"""
def patch_lookup(a): def patch_lookup_lt_18(a):
if django.VERSION < (1, 8):
a.lookup = translate_polymorphic_field_path(self.model, a.lookup) a.lookup = translate_polymorphic_field_path(self.model, a.lookup)
else:
def patch_lookup_gte_18(a):
# With Django > 1.8, the field on which the aggregate operates is # With Django > 1.8, the field on which the aggregate operates is
# stored inside a query expression. # stored inside a complex query expression.
if hasattr(a, 'source_expressions'): if isinstance(a, Q):
a.source_expressions[0].name = translate_polymorphic_field_path( translate_polymorphic_Q_object(self.model, a)
self.model, a.source_expressions[0].name) elif hasattr(a, 'get_source_expressions'):
for source_expression in a.get_source_expressions():
patch_lookup_gte_18(source_expression)
else:
a.name = translate_polymorphic_field_path(self.model, a.name)
get_lookup = lambda a: a.lookup if django.VERSION < (1, 8) else a.source_expressions[0].name get_lookup = lambda a: a.lookup if django.VERSION < (1, 8) else a.source_expressions[0].name
for a in args: for a in args:
assert '___' not in get_lookup(a), 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only' assert '___' not in get_lookup(a), 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'
for a in six.itervalues(kwargs): for a in six.itervalues(kwargs):
patch_lookup = patch_lookup_lt_18 if django.VERSION < (1, 8) else patch_lookup_gte_18
patch_lookup(a) patch_lookup(a)
def annotate(self, *args, **kwargs): def annotate(self, *args, **kwargs):