Skip to content

Commit 5855574

Browse files
committed
Added SelectAndPrefetchForIncludesMixin, deprecated PrefetchForIncludesHelperMixin
1 parent 9f1d999 commit 5855574

File tree

1 file changed

+52
-2
lines changed

1 file changed

+52
-2
lines changed

rest_framework_json_api/views.py

+52-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import warnings
12
from collections import Iterable
23

34
from django.core.exceptions import ImproperlyConfigured
@@ -31,6 +32,13 @@
3132

3233

3334
class PrefetchForIncludesHelperMixin(object):
35+
36+
def __init__(self, *args, **kwargs):
37+
warnings.warn("PrefetchForIncludesHelperMixin is deprecated. "
38+
"Use SelectAndPrefetchForIncludesMixin instead",
39+
DeprecationWarning)
40+
super(PrefetchForIncludesHelperMixin, self).__init__(*args, **kwargs)
41+
3442
def get_queryset(self):
3543
"""
3644
This viewset provides a helper attribute to prefetch related models
@@ -62,10 +70,52 @@ class MyViewSet(viewsets.ModelViewSet):
6270
return qs
6371

6472

73+
class SelectAndPrefetchForIncludesMixin(object):
74+
"""
75+
This mixin provides a helper attributes to select or prefetch related models
76+
based on the include specified in the URL.
77+
78+
__all__ can be used to specify a prefetch which should be done regardless of the include
79+
80+
.. code:: python
81+
82+
# When MyViewSet is called with ?include=author it will prefetch author and authorbio
83+
class MyViewSet(viewsets.ModelViewSet):
84+
queryset = Book.objects.all()
85+
prefetch_for_includes = {
86+
'__all__': [],
87+
'category.section': ['category']
88+
}
89+
select_for_includes = {
90+
'__all__': [],
91+
'author': ['author', 'author__authorbio'],
92+
}
93+
"""
94+
def get_queryset(self):
95+
qs = super(SelectAndPrefetchForIncludesMixin, self).get_queryset()
96+
97+
includes = self.request.GET.get('include', '').split(',') + ['__all__']
98+
99+
if hasattr(self, 'select_for_includes'):
100+
selects = [self.select_for_includes.get(inc) for inc in includes]
101+
qs = qs.select_related(*selects)
102+
103+
if hasattr(self, 'prefetch_for_includes'):
104+
prefetches = [self.prefetch_for_includes.get(inc) for inc in includes]
105+
qs = qs.prefetch_related(*prefetches)
106+
107+
return qs
108+
109+
65110
class AutoPrefetchMixin(object):
66111
def get_queryset(self, *args, **kwargs):
67112
""" This mixin adds automatic prefetching for OneToOne and ManyToMany fields. """
68113
qs = super(AutoPrefetchMixin, self).get_queryset(*args, **kwargs)
114+
115+
# Prefetch includes handled by another mixin, let's do not mix them
116+
if hasattr(self, 'prefetch_for_includes'):
117+
return qs
118+
69119
included_resources = get_included_resources(self.request)
70120

71121
for included in included_resources:
@@ -187,14 +237,14 @@ def get_related_instance(self):
187237

188238

189239
class ModelViewSet(AutoPrefetchMixin,
190-
PrefetchForIncludesHelperMixin,
240+
SelectAndPrefetchForIncludesMixin,
191241
RelatedMixin,
192242
viewsets.ModelViewSet):
193243
pass
194244

195245

196246
class ReadOnlyModelViewSet(AutoPrefetchMixin,
197-
PrefetchForIncludesHelperMixin,
247+
SelectAndPrefetchForIncludesMixin,
198248
RelatedMixin,
199249
viewsets.ReadOnlyModelViewSet):
200250
pass

0 commit comments

Comments
 (0)