mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-12-01 22:14:06 +03:00
simplified, moved field humanizing to Field. broken tests
This commit is contained in:
parent
dea0b6ab7f
commit
a1deb5eac7
|
@ -31,36 +31,6 @@ from rest_framework.compat import smart_text, force_text, is_non_str_iterable
|
||||||
from rest_framework.settings import api_settings
|
from rest_framework.settings import api_settings
|
||||||
|
|
||||||
|
|
||||||
HUMANIZED_FIELD_TYPES = {
|
|
||||||
'BooleanField': u'Boolean',
|
|
||||||
'CharField': u'String',
|
|
||||||
'ChoiceField': u'Single Choice',
|
|
||||||
'ComboField': u'Single Choice',
|
|
||||||
'DateField': u'Date',
|
|
||||||
'DateTimeField': u'Date and Time',
|
|
||||||
'DecimalField': u'Decimal',
|
|
||||||
'EmailField': u'Email',
|
|
||||||
'Field': u'Field',
|
|
||||||
'FileField': u'File',
|
|
||||||
'FilePathField': u'File Path',
|
|
||||||
'FloatField': u'Float',
|
|
||||||
'GenericIPAddressField': u'Generic IP Address',
|
|
||||||
'IPAddressField': u'IP Address',
|
|
||||||
'ImageField': u'Image',
|
|
||||||
'IntegerField': u'Integer',
|
|
||||||
'MultiValueField': u'Multiple Value',
|
|
||||||
'MultipleChoiceField': u'Multiple Choice',
|
|
||||||
'NullBooleanField': u'Nullable Boolean',
|
|
||||||
'RegexField': u'Regular Expression',
|
|
||||||
'SlugField': u'Slug',
|
|
||||||
'SplitDateTimeField': u'Split Date and Time',
|
|
||||||
'TimeField': u'Time',
|
|
||||||
'TypedChoiceField': u'Typed Single Choice',
|
|
||||||
'TypedMultipleChoiceField': u'Typed Multiple Choice',
|
|
||||||
'URLField': u'URL',
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def is_simple_callable(obj):
|
def is_simple_callable(obj):
|
||||||
"""
|
"""
|
||||||
True if the object is a callable that takes no arguments.
|
True if the object is a callable that takes no arguments.
|
||||||
|
@ -102,49 +72,6 @@ def readable_date_formats(formats):
|
||||||
return humanize_strptime(format)
|
return humanize_strptime(format)
|
||||||
|
|
||||||
|
|
||||||
def humanize_field_type(field_type):
|
|
||||||
"""Return a human-readable name for a field type.
|
|
||||||
|
|
||||||
:param field_type: Either a field type class (for example
|
|
||||||
django.forms.fields.DateTimeField), or the name of a field type
|
|
||||||
(for example "DateTimeField").
|
|
||||||
|
|
||||||
:return: unicode
|
|
||||||
|
|
||||||
"""
|
|
||||||
if isinstance(field_type, basestring):
|
|
||||||
field_type_name = field_type
|
|
||||||
else:
|
|
||||||
field_type_name = field_type.__name__
|
|
||||||
try:
|
|
||||||
return HUMANIZED_FIELD_TYPES[field_type_name]
|
|
||||||
except KeyError:
|
|
||||||
humanized = re.sub('([a-z0-9])([A-Z])', r'\1 \2', field_type_name)
|
|
||||||
return humanized.capitalize()
|
|
||||||
|
|
||||||
|
|
||||||
def humanize_field(field):
|
|
||||||
"""Return a human-readable description of a field.
|
|
||||||
|
|
||||||
:param field: A Django field.
|
|
||||||
|
|
||||||
:return: A dictionary of the form {type: type name, required: bool,
|
|
||||||
label: field label: read_only: bool,
|
|
||||||
help_text: optional help text}
|
|
||||||
|
|
||||||
"""
|
|
||||||
humanized = {
|
|
||||||
'type': humanize_field_type(field.__class__),
|
|
||||||
'required': getattr(field, 'required', False),
|
|
||||||
}
|
|
||||||
optional_attrs = ['read_only', 'help_text', 'label',
|
|
||||||
'min_length', 'max_length']
|
|
||||||
for attr in optional_attrs:
|
|
||||||
if getattr(field, attr, None) is not None:
|
|
||||||
humanized[attr] = getattr(field, attr)
|
|
||||||
return humanized
|
|
||||||
|
|
||||||
|
|
||||||
def humanize_form_fields(form):
|
def humanize_form_fields(form):
|
||||||
"""Return a humanized description of all the fields in a form.
|
"""Return a humanized description of all the fields in a form.
|
||||||
|
|
||||||
|
@ -274,6 +201,19 @@ class Field(object):
|
||||||
return {'type': self.type_name}
|
return {'type': self.type_name}
|
||||||
return {}
|
return {}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def humanized(self):
|
||||||
|
humanized = {
|
||||||
|
'type': self.type_name,
|
||||||
|
'required': getattr(self, 'required', False),
|
||||||
|
}
|
||||||
|
optional_attrs = ['read_only', 'help_text', 'label',
|
||||||
|
'min_length', 'max_length']
|
||||||
|
for attr in optional_attrs:
|
||||||
|
if getattr(self, attr, None) is not None:
|
||||||
|
humanized[attr] = getattr(self, attr)
|
||||||
|
return humanized
|
||||||
|
|
||||||
|
|
||||||
class WritableField(Field):
|
class WritableField(Field):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -521,6 +521,13 @@ class BaseSerializer(WritableField):
|
||||||
|
|
||||||
return self.object
|
return self.object
|
||||||
|
|
||||||
|
@property
|
||||||
|
def humanized(self):
|
||||||
|
humanized_fields = SortedDict(
|
||||||
|
[(name, field.humanized)
|
||||||
|
for name, field in self.fields.iteritems()])
|
||||||
|
return humanized_fields
|
||||||
|
|
||||||
|
|
||||||
class Serializer(six.with_metaclass(SerializerMetaclass, BaseSerializer)):
|
class Serializer(six.with_metaclass(SerializerMetaclass, BaseSerializer)):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -15,8 +15,7 @@ from django.test import TestCase
|
||||||
from django.utils.datastructures import SortedDict
|
from django.utils.datastructures import SortedDict
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.fields import (humanize_field, humanize_field_type,
|
from rest_framework.fields import Field, CharField
|
||||||
humanize_form_fields, Field)
|
|
||||||
from rest_framework.serializers import Serializer
|
from rest_framework.serializers import Serializer
|
||||||
from rest_framework.tests.models import RESTFrameworkModel
|
from rest_framework.tests.models import RESTFrameworkModel
|
||||||
|
|
||||||
|
@ -768,14 +767,16 @@ class SlugFieldTests(TestCase):
|
||||||
|
|
||||||
def test_given_serializer_value(self):
|
def test_given_serializer_value(self):
|
||||||
class SlugFieldSerializer(serializers.ModelSerializer):
|
class SlugFieldSerializer(serializers.ModelSerializer):
|
||||||
slug_field = serializers.SlugField(source='slug_field', max_length=20, required=False)
|
slug_field = serializers.SlugField(source='slug_field',
|
||||||
|
max_length=20, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = self.SlugFieldModel
|
model = self.SlugFieldModel
|
||||||
|
|
||||||
serializer = SlugFieldSerializer(data={})
|
serializer = SlugFieldSerializer(data={})
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
self.assertEqual(getattr(serializer.fields['slug_field'], 'max_length'), 20)
|
self.assertEqual(getattr(serializer.fields['slug_field'],
|
||||||
|
'max_length'), 20)
|
||||||
|
|
||||||
|
|
||||||
class URLFieldTests(TestCase):
|
class URLFieldTests(TestCase):
|
||||||
|
@ -796,7 +797,8 @@ class URLFieldTests(TestCase):
|
||||||
|
|
||||||
serializer = URLFieldSerializer(data={})
|
serializer = URLFieldSerializer(data={})
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
self.assertEqual(getattr(serializer.fields['url_field'], 'max_length'), 200)
|
self.assertEqual(getattr(serializer.fields['url_field'],
|
||||||
|
'max_length'), 200)
|
||||||
|
|
||||||
def test_given_model_value(self):
|
def test_given_model_value(self):
|
||||||
class URLFieldSerializer(serializers.ModelSerializer):
|
class URLFieldSerializer(serializers.ModelSerializer):
|
||||||
|
@ -805,48 +807,21 @@ class URLFieldTests(TestCase):
|
||||||
|
|
||||||
serializer = URLFieldSerializer(data={})
|
serializer = URLFieldSerializer(data={})
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
self.assertEqual(getattr(serializer.fields['url_field'], 'max_length'), 128)
|
self.assertEqual(getattr(serializer.fields['url_field'],
|
||||||
|
'max_length'), 128)
|
||||||
|
|
||||||
def test_given_serializer_value(self):
|
def test_given_serializer_value(self):
|
||||||
class URLFieldSerializer(serializers.ModelSerializer):
|
class URLFieldSerializer(serializers.ModelSerializer):
|
||||||
url_field = serializers.URLField(source='url_field', max_length=20, required=False)
|
url_field = serializers.URLField(source='url_field',
|
||||||
|
max_length=20, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = self.URLFieldWithGivenMaxLengthModel
|
model = self.URLFieldWithGivenMaxLengthModel
|
||||||
|
|
||||||
serializer = URLFieldSerializer(data={})
|
serializer = URLFieldSerializer(data={})
|
||||||
self.assertEqual(serializer.is_valid(), True)
|
self.assertEqual(serializer.is_valid(), True)
|
||||||
self.assertEqual(getattr(serializer.fields['url_field'], 'max_length'), 20)
|
self.assertEqual(getattr(serializer.fields['url_field'],
|
||||||
|
'max_length'), 20)
|
||||||
|
|
||||||
class HumanizedFieldType(TestCase):
|
|
||||||
def test_standard_type_classes(self):
|
|
||||||
for field_type_name in forms.fields.__all__:
|
|
||||||
field_type = getattr(forms.fields, field_type_name)
|
|
||||||
humanized = humanize_field_type(field_type)
|
|
||||||
self.assert_valid_name(humanized)
|
|
||||||
|
|
||||||
def test_standard_type_names(self):
|
|
||||||
for field_type_name in forms.fields.__all__:
|
|
||||||
humanized = humanize_field_type(field_type_name)
|
|
||||||
self.assert_valid_name(humanized)
|
|
||||||
|
|
||||||
def test_custom_type_name(self):
|
|
||||||
humanized = humanize_field_type('SomeCustomType')
|
|
||||||
self.assertEquals(humanized, u'Some custom type')
|
|
||||||
|
|
||||||
def test_custom_type(self):
|
|
||||||
custom_type = namedtuple('SomeCustomType', [])
|
|
||||||
humanized = humanize_field_type(custom_type)
|
|
||||||
self.assertEquals(humanized, u'Some custom type')
|
|
||||||
|
|
||||||
def assert_valid_name(self, humanized):
|
|
||||||
"""A humanized field name is valid if it's a non-empty
|
|
||||||
unicode.
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.assertIsInstance(humanized, unicode)
|
|
||||||
self.assertNotEqual(humanized, '')
|
|
||||||
|
|
||||||
|
|
||||||
class HumanizedField(TestCase):
|
class HumanizedField(TestCase):
|
||||||
|
@ -859,37 +834,41 @@ class HumanizedField(TestCase):
|
||||||
self.optional_field.label = uuid4().hex
|
self.optional_field.label = uuid4().hex
|
||||||
self.optional_field.required = False
|
self.optional_field.required = False
|
||||||
|
|
||||||
|
def test_type(self):
|
||||||
|
for field in (self.required_field, self.optional_field):
|
||||||
|
self.assertEqual(field.humanized['type'], field.type_name)
|
||||||
|
|
||||||
def test_required(self):
|
def test_required(self):
|
||||||
self.assertEqual(humanize_field(self.required_field)['required'], True)
|
self.assertEqual(self.required_field.humanized['required'], True)
|
||||||
|
|
||||||
def test_optional(self):
|
def test_optional(self):
|
||||||
self.assertEqual(humanize_field(self.optional_field)['required'],
|
self.assertEqual(self.optional_field.humanized['required'], False)
|
||||||
False)
|
|
||||||
|
|
||||||
def test_label(self):
|
def test_label(self):
|
||||||
for field in (self.required_field, self.optional_field):
|
for field in (self.required_field, self.optional_field):
|
||||||
self.assertEqual(humanize_field(field)['label'], field.label)
|
self.assertEqual(field.humanized['label'], field.label)
|
||||||
|
|
||||||
|
|
||||||
class Form(forms.Form):
|
class HumanizableSerializer(Serializer):
|
||||||
field1 = forms.CharField(max_length=3, label='field one')
|
field1 = CharField(3, required=True)
|
||||||
field2 = forms.CharField(label='field two')
|
field2 = CharField(10, required=False)
|
||||||
|
|
||||||
|
|
||||||
class HumanizedSerializer(TestCase):
|
class HumanizedSerializer(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.serializer = TimestampedModelSerializer()
|
self.serializer = HumanizableSerializer()
|
||||||
|
|
||||||
def test_humanized(self):
|
def test_humanized(self):
|
||||||
humanized = humanize_form_fields(Form())
|
humanized = self.serializer.humanized
|
||||||
expected = {
|
expected = {
|
||||||
'field1': {u'help_text': u'',
|
'field1': {u'required': True,
|
||||||
u'label': u'field one',
|
|
||||||
u'max_length': 3,
|
u'max_length': 3,
|
||||||
u'required': True,
|
u'type': u'CharField',
|
||||||
u'type': u'String'},
|
u'read_only': False},
|
||||||
'field2': {u'help_text': u'',
|
'field2': {u'required': False,
|
||||||
u'label': u'field two',
|
u'max_length': 10,
|
||||||
u'required': True,
|
u'type': u'CharField',
|
||||||
u'type': u'String'}}
|
u'read_only': False}}
|
||||||
self.assertEqual(humanized, expected)
|
self.assertEqual(set(expected.keys()), set(humanized.keys()))
|
||||||
|
for k, v in humanized.iteritems():
|
||||||
|
self.assertEqual(v, expected[k])
|
||||||
|
|
|
@ -91,7 +91,7 @@ class APIView(View):
|
||||||
continue
|
continue
|
||||||
serializer = self.get_serializer()
|
serializer = self.get_serializer()
|
||||||
if serializer is not None:
|
if serializer is not None:
|
||||||
actions[method] = humanize_form_fields(serializer)
|
actions[method] = serializer.humanized
|
||||||
except exceptions.PermissionDenied:
|
except exceptions.PermissionDenied:
|
||||||
# don't add this method
|
# don't add this method
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue
Block a user