Skip to content

Commit

Permalink
Migrate from unused in Django 1.11 qs.iterator() to custom qs._iterab…
Browse files Browse the repository at this point in the history
…le_class
  • Loading branch information
un-def committed Apr 19, 2017
1 parent a568c04 commit dbad7bd
Showing 1 changed file with 50 additions and 46 deletions.
96 changes: 50 additions & 46 deletions polymorphic/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@
from collections import defaultdict

import django
from django.db.models.query import QuerySet, Q
from django.db.models.query import ModelIterable, QuerySet, Q
from django.contrib.contenttypes.models import ContentType
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_field_path, translate_polymorphic_Q_object

# 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 PolymorphicModelIterable; we use the same chunk size as Django
try:
from django.db.models.query import CHUNK_SIZE # this is 100 for Django 1.1/1.2
except ImportError:
Expand All @@ -25,6 +25,52 @@
Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE


class PolymorphicModelIterable(ModelIterable):
"""
ModelIterable for PolymorphicModel
Yields real instances if qs.polymorphic_disabled is False,
otherwise acts like a regular ModelIterable.
"""

def __iter__(self):
base_iter = super(PolymorphicModelIterable, self).__iter__()
if self.queryset.polymorphic_disabled:
return base_iter
return self._polymorhic_iterator(base_iter)

def _polymorhic_iterator(self, base_iter):
"""
Here we do the same as::
base_result_objects = list(super(PolymorphicModelIterable, self).__iter__())
real_results = self.queryset._get_real_instances(base_result_objects)
for o in real_results: yield o
but it requests the objects in chunks from the database,
with Polymorphic_QuerySet_objects_per_request per chunk
"""
while True:
base_result_objects = []
reached_end = False

for i in range(Polymorphic_QuerySet_objects_per_request):
try:
o = next(base_iter)
base_result_objects.append(o)
except StopIteration:
reached_end = True
break

real_results = self.queryset._get_real_instances(base_result_objects)

for o in real_results:
yield o

if reached_end:
return


def transmogrify(cls, obj):
"""
Upcast a class to a different type without asking questions.
Expand Down Expand Up @@ -63,6 +109,8 @@ class PolymorphicQuerySet(QuerySet):
"""

def __init__(self, *args, **kwargs):
super(PolymorphicQuerySet, self).__init__(*args, **kwargs)
self._iterable_class = PolymorphicModelIterable
# init our queryset object member variables
self.polymorphic_disabled = False
# A parallel structure to django.db.models.query.Query.deferred_loading,
Expand All @@ -71,7 +119,6 @@ def __init__(self, *args, **kwargs):
# retrieving the real instance (so that the deferred fields apply
# to that queryset as well).
self.polymorphic_deferred_loading = (set([]), True)
super(PolymorphicQuerySet, self).__init__(*args, **kwargs)

def _clone(self, *args, **kwargs):
# Django's _clone only copies its own variables, so we need to copy ours here
Expand Down Expand Up @@ -407,49 +454,6 @@ class self.model, but as a class derived from self.model. We want to re-fetch

return resultlist

def iterator(self):
"""
This function is used by Django for all object retrieval.
By overriding it, we modify the objects that this queryset returns
when it is evaluated (or its get method or other object-returning methods are called).
Here we do the same as::
base_result_objects = list(super(PolymorphicQuerySet, self).iterator())
real_results = self._get_real_instances(base_result_objects)
for o in real_results: yield o
but it requests the objects in chunks from the database,
with Polymorphic_QuerySet_objects_per_request per chunk
"""
base_iter = super(PolymorphicQuerySet, self).iterator()

# disabled => work just like a normal queryset
if self.polymorphic_disabled:
for o in base_iter:
yield o
return

while True:
base_result_objects = []
reached_end = False

for i in range(Polymorphic_QuerySet_objects_per_request):
try:
o = next(base_iter)
base_result_objects.append(o)
except StopIteration:
reached_end = True
break

real_results = self._get_real_instances(base_result_objects)

for o in real_results:
yield o

if reached_end:
return

def __repr__(self, *args, **kwargs):
if self.model.polymorphic_query_multiline_output:
result = [repr(o) for o in self.all()]
Expand Down

0 comments on commit dbad7bd

Please sign in to comment.