|
2 | 2 | from operator import attrgetter
|
3 | 3 |
|
4 | 4 | from django.db import models
|
| 5 | +from django.db.models.query_utils import select_related_descend |
5 | 6 |
|
6 | 7 | cached_value_getter = attrgetter("get_cached_value")
|
7 | 8 |
|
8 | 9 |
|
9 |
| -def get_select_related_getters(lookups, opts): |
| 10 | +def get_restricted_select_related_getters(lookups, opts): |
10 | 11 | """Turn a select_related dict structure into a tree of attribute getters"""
|
11 | 12 | for lookup, nested_lookups in lookups.items():
|
12 | 13 | field = opts.get_field(lookup)
|
13 | 14 | lookup_opts = field.related_model._meta
|
14 | 15 | yield (
|
15 | 16 | cached_value_getter(field),
|
16 |
| - tuple(get_select_related_getters(nested_lookups, lookup_opts)), |
| 17 | + tuple(get_restricted_select_related_getters(nested_lookups, lookup_opts)), |
| 18 | + ) |
| 19 | + |
| 20 | + |
| 21 | +def get_unrestricted_select_related_getters(opts, max_depth, cur_depth=1): |
| 22 | + if cur_depth > max_depth: |
| 23 | + return |
| 24 | + for field in opts.fields: |
| 25 | + if not select_related_descend(field, False, None, {}): |
| 26 | + continue |
| 27 | + related_model_meta = field.related_model._meta |
| 28 | + yield ( |
| 29 | + cached_value_getter(field), |
| 30 | + tuple( |
| 31 | + get_unrestricted_select_related_getters( |
| 32 | + related_model_meta, max_depth=max_depth, cur_depth=cur_depth + 1 |
| 33 | + ) |
| 34 | + ), |
17 | 35 | )
|
18 | 36 |
|
19 | 37 |
|
@@ -44,12 +62,22 @@ def _sealed_related_iterator(self, related_walker):
|
44 | 62 | yield obj
|
45 | 63 |
|
46 | 64 | def __iter__(self):
|
47 |
| - select_related = self.queryset.query.select_related |
| 65 | + query = self.queryset.query |
| 66 | + select_related = query.select_related |
48 | 67 | if select_related:
|
49 | 68 | opts = self.queryset.model._meta
|
50 |
| - select_related_getters = tuple( |
51 |
| - get_select_related_getters(self.queryset.query.select_related, opts) |
52 |
| - ) |
| 69 | + if isinstance(select_related, dict): |
| 70 | + select_related_getters = tuple( |
| 71 | + get_restricted_select_related_getters( |
| 72 | + self.queryset.query.select_related, opts |
| 73 | + ) |
| 74 | + ) |
| 75 | + else: |
| 76 | + select_related_getters = tuple( |
| 77 | + get_unrestricted_select_related_getters( |
| 78 | + opts, max_depth=query.max_depth |
| 79 | + ) |
| 80 | + ) |
53 | 81 | related_walker = partial(
|
54 | 82 | walk_select_relateds, getters=select_related_getters
|
55 | 83 | )
|
|
0 commit comments