Skip to content

Commit 189e613

Browse files
authored
Merge pull request #172 from rpkilby/exclude-request-interaction
Prevent deepcopying of filter's parent
2 parents ac68223 + 08d518d commit 189e613

File tree

2 files changed

+41
-4
lines changed

2 files changed

+41
-4
lines changed

rest_framework_filters/filterset.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,13 @@ def expand_filters(self):
115115

116116
# include exclusion keys
117117
if exclude_name in self.data:
118-
f = copy.deepcopy(f)
119-
f.exclude = not f.exclude
120-
requested_filters[exclude_name] = f
118+
# deepcopy the *base* filter to prevent copying of model & parent
119+
f_copy = copy.deepcopy(self.base_filters[filter_name])
120+
f_copy.parent = f.parent
121+
f_copy.model = f.model
122+
f_copy.exclude = not f.exclude
123+
124+
requested_filters[exclude_name] = f_copy
121125

122126
# include filters from related subsets
123127
if isinstance(f, filters.RelatedFilter) and filter_name in related_data:

tests/test_filterset.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
from __future__ import absolute_import
33
from __future__ import unicode_literals
44

5+
import sys
6+
57
from django.test import TestCase
68
from django.utils import six
79

@@ -11,7 +13,7 @@
1113
from django_filters.filters import BaseInFilter
1214

1315
from .testapp.models import (
14-
User, Note, Post, Person, Tag, BlogPost,
16+
Note, Post, Person, Tag, BlogPost,
1517
)
1618

1719
from .testapp.filters import (
@@ -24,6 +26,21 @@
2426
BlogPostOverrideFilter,
2527
)
2628

29+
from rest_framework.views import APIView
30+
from rest_framework.test import APIRequestFactory
31+
factory = APIRequestFactory()
32+
33+
34+
class limit_recursion:
35+
def __init__(self):
36+
self.original_limit = sys.getrecursionlimit()
37+
38+
def __enter__(self):
39+
sys.setrecursionlimit(100)
40+
41+
def __exit__(self, *args):
42+
sys.setrecursionlimit(self.original_limit)
43+
2744

2845
class LookupsFilterTests(TestCase):
2946
"""
@@ -429,3 +446,19 @@ def test_related_exclusion_results(self):
429446

430447
self.assertEqual(len(results), 1)
431448
self.assertEqual(results[0], 'Post 2')
449+
450+
def test_exclude_and_request_interaction(self):
451+
# See: https://github.com/philipn/django-rest-framework-filters/issues/171
452+
request = APIView().initialize_request(factory.get('/?tags__name__contains!=Tag'))
453+
filterset = BlogPostFilter(request.query_params, request=request, queryset=BlogPost.objects.all())
454+
455+
try:
456+
with limit_recursion():
457+
qs = filterset.qs
458+
except RuntimeError:
459+
self.fail('Recursion limit reached')
460+
461+
results = [r.title for r in qs]
462+
463+
self.assertEqual(len(results), 1)
464+
self.assertEqual(results[0], 'Post 2')

0 commit comments

Comments
 (0)