From a6732e25ecaaed706d1c76aa1be79ffa0d868213 Mon Sep 17 00:00:00 2001 From: Simon Charette Date: Tue, 29 Mar 2016 13:25:26 -0400 Subject: [PATCH] Fixed #3751 -- Stopped listing related field choices through metadata. Listing related fields can leak sensitive data and result in poor performance when dealing with large result sets. Large result sets should be exposed by a dedicated endpoint instead. --- rest_framework/metadata.py | 4 +++- tests/test_metadata.py | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/rest_framework/metadata.py b/rest_framework/metadata.py index 6c4f17692..673aa962c 100644 --- a/rest_framework/metadata.py +++ b/rest_framework/metadata.py @@ -137,7 +137,9 @@ class SimpleMetadata(BaseMetadata): elif getattr(field, 'fields', None): field_info['children'] = self.get_serializer_info(field) - if not field_info.get('read_only') and hasattr(field, 'choices'): + if (not field_info.get('read_only') and + not isinstance(field, serializers.RelatedField) and + hasattr(field, 'choices')): field_info['choices'] = [ { 'value': choice_value, diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 6819f1504..109dd3f7c 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -11,6 +11,8 @@ from rest_framework.renderers import BrowsableAPIRenderer from rest_framework.request import Request from rest_framework.test import APIRequestFactory +from .models import BasicModel + request = Request(APIRequestFactory().options('/')) @@ -261,10 +263,21 @@ class TestMetadata: view = ExampleView.as_view(versioning_class=scheme) view(request=request) + +class TestSimpleMetadataFieldInfo(TestCase): def test_null_boolean_field_info_type(self): options = metadata.SimpleMetadata() field_info = options.get_field_info(serializers.NullBooleanField()) - assert field_info['type'] == 'boolean' + self.assertEqual(field_info['type'], 'boolean') + + def test_related_field_choices(self): + options = metadata.SimpleMetadata() + BasicModel.objects.create() + with self.assertNumQueries(0): + field_info = options.get_field_info( + serializers.RelatedField(queryset=BasicModel.objects.all()) + ) + self.assertNotIn('choices', field_info) class TestModelSerializerMetadata(TestCase):