Skip to content

Commit add2825

Browse files
author
Jannon Frank
committed
fix read_only related field metadata
1 parent 6634ce0 commit add2825

File tree

2 files changed

+91
-8
lines changed

2 files changed

+91
-8
lines changed

rest_framework/metadata.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,14 @@ def get_field_info(self, field):
127127
if value is not None and value != '':
128128
field_info[attr] = force_text(value, strings_only=True)
129129

130-
if hasattr(field, 'choices'):
131-
field_info['choices'] = [
132-
{
133-
'value': choice_value,
134-
'display_name': force_text(choice_name, strings_only=True)
135-
}
136-
for choice_value, choice_name in field.choices.items()
137-
]
130+
if 'read_only' in field_info and not field_info['read_only']:
131+
if hasattr(field, 'choices'):
132+
field_info['choices'] = [
133+
{
134+
'value': choice_value,
135+
'display_name': force_text(choice_name, strings_only=True)
136+
}
137+
for choice_value, choice_name in field.choices.items()
138+
]
138139

139140
return field_info

tests/test_metadata.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
from __future__ import unicode_literals
2+
from django.db import models
3+
from django.test import TestCase
4+
from django.core.validators import MinValueValidator, MaxValueValidator, MinLengthValidator
25
from rest_framework import exceptions, metadata, serializers, status, views, versioning
36
from rest_framework.request import Request
47
from rest_framework.renderers import BrowsableAPIRenderer
@@ -212,3 +215,82 @@ def test_null_boolean_field_info_type(self):
212215
options = metadata.SimpleMetadata()
213216
field_info = options.get_field_info(serializers.NullBooleanField())
214217
assert field_info['type'] == 'boolean'
218+
219+
220+
class TestModelSerializerMetadata(TestCase):
221+
def test_read_only_primary_key_related_field(self):
222+
"""
223+
On generic views OPTIONS should return an 'actions' key with metadata
224+
on the fields that may be supplied to PUT and POST requests. It should
225+
not fail when a read_only PrimaryKeyRelatedField is present
226+
"""
227+
class Parent(models.Model):
228+
integer_field = models.IntegerField(validators=[MinValueValidator(1), MaxValueValidator(1000)])
229+
children = models.ManyToManyField('Child')
230+
name = models.CharField(max_length=100, blank=True, null=True)
231+
232+
class Child(models.Model):
233+
name = models.CharField(max_length=100)
234+
235+
class ExampleSerializer(serializers.ModelSerializer):
236+
children = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
237+
class Meta:
238+
model = Parent
239+
240+
class ExampleView(views.APIView):
241+
"""Example view."""
242+
def post(self, request):
243+
pass
244+
245+
def get_serializer(self):
246+
return ExampleSerializer()
247+
248+
view = ExampleView.as_view()
249+
response = view(request=request)
250+
expected = {
251+
'name': 'Example',
252+
'description': 'Example view.',
253+
'renders': [
254+
'application/json',
255+
'text/html'
256+
],
257+
'parses': [
258+
'application/json',
259+
'application/x-www-form-urlencoded',
260+
'multipart/form-data'
261+
],
262+
'actions': {
263+
'POST': {
264+
'id': {
265+
'type': 'integer',
266+
'required': False,
267+
'read_only': True,
268+
'label': 'ID'
269+
},
270+
'children': {
271+
'type': 'field',
272+
'required': False,
273+
'read_only': True,
274+
'label': 'Children'
275+
},
276+
'integer_field': {
277+
'type': 'integer',
278+
'required': True,
279+
'read_only': False,
280+
'label': 'Integer field',
281+
'min_value': 1,
282+
'max_value': 1000
283+
},
284+
'name': {
285+
'type': 'string',
286+
'required': False,
287+
'read_only': False,
288+
'label': 'Name',
289+
'max_length': 100
290+
}
291+
}
292+
}
293+
}
294+
295+
assert response.status_code == status.HTTP_200_OK
296+
assert response.data == expected

0 commit comments

Comments
 (0)