Skip to content

Commit 24791cb

Browse files
Invalidate any existing prefetch cache on PUT requests. (#4668)
1 parent 8bab7f8 commit 24791cb

3 files changed

Lines changed: 31 additions & 5 deletions

File tree

docs/api-guide/testing.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,12 @@ As usual CSRF validation will only apply to any session authenticated views. Th
187187
# RequestsClient
188188

189189
REST framework also includes a client for interacting with your application
190-
using the popular Python library, `requests`.
190+
using the popular Python library, `requests`. This may be useful if:
191+
192+
* You are expecting to interface with the API primarily from another Python service,
193+
and want to test the service at the same level as the client will see.
194+
* You want to write tests in such a way that they can also be run against a staging or
195+
live environment. (See "Live tests" below.)
191196

192197
This exposes exactly the same interface as if you were using a requests session
193198
directly.
@@ -198,6 +203,10 @@ directly.
198203

199204
Note that the requests client requires you to pass fully qualified URLs.
200205

206+
## `RequestsClient` and working with the database
207+
208+
The `RequestsClient` class is useful if
209+
201210
## Headers & Authentication
202211

203212
Custom headers and authentication credentials can be provided in the same way

rest_framework/mixins.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,8 @@ def update(self, request, *args, **kwargs):
7171

7272
if getattr(instance, '_prefetched_objects_cache', None):
7373
# If 'prefetch_related' has been applied to a queryset, we need to
74-
# refresh the instance from the database.
75-
instance = self.get_object()
76-
serializer = self.get_serializer(instance)
74+
# forcibly invalidate the prefetch cache on the instance.
75+
instance._prefetched_objects_cache = {}
7776

7877
return Response(serializer.data)
7978

tests/test_prefetch_related.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class Meta:
1414

1515

1616
class UserUpdate(generics.UpdateAPIView):
17-
queryset = User.objects.all().prefetch_related('groups')
17+
queryset = User.objects.exclude(username='exclude').prefetch_related('groups')
1818
serializer_class = UserSerializer
1919

2020

@@ -39,3 +39,21 @@ def test_prefetch_related_updates(self):
3939
'email': 'tom@example.com'
4040
}
4141
assert response.data == expected
42+
43+
def test_prefetch_related_excluding_instance_from_original_queryset(self):
44+
"""
45+
Regression test for https://github.com/tomchristie/django-rest-framework/issues/4661
46+
"""
47+
view = UserUpdate.as_view()
48+
pk = self.user.pk
49+
groups_pk = self.groups[0].pk
50+
request = factory.put('/', {'username': 'exclude', 'groups': [groups_pk]}, format='json')
51+
response = view(request, pk=pk)
52+
assert User.objects.get(pk=pk).groups.count() == 1
53+
expected = {
54+
'id': pk,
55+
'username': 'exclude',
56+
'groups': [1],
57+
'email': 'tom@example.com'
58+
}
59+
assert response.data == expected

0 commit comments

Comments
 (0)