From c3a6e4c1fd8e527ca0c375ee5b16d49b1b745857 Mon Sep 17 00:00:00 2001 From: Ryo Chijiiwa Date: Fri, 26 Jul 2019 21:44:10 -0700 Subject: [PATCH 1/3] fix bug where implicit prefetch and explicit prefetch behaviors were inconsistent --- dynamic_rest/filters.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/dynamic_rest/filters.py b/dynamic_rest/filters.py index 91855d05..74eea336 100644 --- a/dynamic_rest/filters.py +++ b/dynamic_rest/filters.py @@ -518,6 +518,18 @@ def _build_queryset( requirements ) + # Implicit requirements (i.e. via `requires`) can potentially + # include fields that haven't been explicitly included. + # Such fields would not be in `fields`, so they need to be added. + implicitly_included = set(requirements.keys()) - set(fields.keys()) + if implicitly_included: + all_fields = serializer.get_all_fields() + fields.update({ + field: all_fields[field] + for field in implicitly_included + if field in all_fields + }) + if filters is None: filters = self._get_requested_filters() From ad83e224dfcbceaf51d02ab6206d8cea18738c6e Mon Sep 17 00:00:00 2001 From: Ryo Chijiiwa Date: Thu, 1 Aug 2019 18:17:20 -0700 Subject: [PATCH 2/3] add test --- tests/serializers.py | 6 +++++- tests/test_api.py | 45 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/tests/serializers.py b/tests/serializers.py index b9d0aaca..d512caa4 100644 --- a/tests/serializers.py +++ b/tests/serializers.py @@ -59,11 +59,15 @@ class Meta: 'cats', 'friendly_cats', 'bad_cats' ) + def filter_queryset(self, query): + return query.exclude(name='Atlantis') + users = DynamicRelationField( 'UserSerializer', source='user_set', many=True, - deferred=True) + deferred=True + ) user_count = CountField('users', required=False, deferred=True) address = DynamicField(source='blob', required=False, deferred=True) cats = DynamicRelationField( diff --git a/tests/test_api.py b/tests/test_api.py index 683fef14..bb7e1097 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -827,6 +827,51 @@ def test_get_with_request_filters_and_requires(self): }] }, json.loads(response.content.decode('utf-8'))) + def test_implicit_vs_explicit_prefetch(self): + """ + LocationSerializer has a built-in filter to hide Atlantis. + UserSerializer can explicitly include Location, and it can also + implicitly require Location through the `number_of_cats` field. + This test ensures that LocationSerializer.filter_queryset() is + being respected regardless of whether `User.location` is being + included implicitly or explicitly. + """ + atlantis = Location.objects.create(name='Atlantis') + atlantian = User.objects.create( + name='Atlantian', + last_name='Human', + location=atlantis + ) + Cat.objects.create( + name='Gato', + home=atlantis, + backup_home=self.fixture.locations[0], + ) + + url = ( + '/users/%s/?' + 'include[]=number_of_cats&' + 'include[]=location.' + ) % atlantian.pk + response1 = self._get_json(url) + + url = ( + '/users/%s/?' + 'include[]=number_of_cats&' + 'exclude[]=location' + ) % atlantian.pk + response2 = self._get_json(url) + + # Atlantis is hidden, therefore its cats are also hidden + self.assertEqual( + response1['user']['number_of_cats'], + 0 + ) + self.assertEqual( + response1['user']['number_of_cats'], + response2['user']['number_of_cats'] + ) + def test_boolean_filters_on_boolean_field(self): # create one dead user User.objects.create(name='Dead', last_name='Mort', is_dead=True) From 5d10f92cb7f5a9b902595c395560c8bd585d2008 Mon Sep 17 00:00:00 2001 From: Ryo Chijiiwa Date: Mon, 12 Aug 2019 12:07:45 -0700 Subject: [PATCH 3/3] move filter function --- tests/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/serializers.py b/tests/serializers.py index d512caa4..21045c52 100644 --- a/tests/serializers.py +++ b/tests/serializers.py @@ -59,9 +59,6 @@ class Meta: 'cats', 'friendly_cats', 'bad_cats' ) - def filter_queryset(self, query): - return query.exclude(name='Atlantis') - users = DynamicRelationField( 'UserSerializer', source='user_set', @@ -77,6 +74,9 @@ def filter_queryset(self, query): bad_cats = DynamicRelationField( 'CatSerializer', source='annoying_cats', many=True, deferred=True) + def filter_queryset(self, query): + return query.exclude(name='Atlantis') + class PermissionSerializer(DynamicModelSerializer):