From 4dffcb5d77a575793c1dc7c1db5242a3ac2d7345 Mon Sep 17 00:00:00 2001 From: Oscar Vilaplana Date: Sat, 18 May 2013 18:10:17 +0200 Subject: Added humanized field names and types --- rest_framework/fields.py | 91 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 2 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 491aa7ed..b23813ec 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -23,13 +23,44 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.datastructures import SortedDict from rest_framework import ISO_8601 -from rest_framework.compat import timezone, parse_date, parse_datetime, parse_time +from rest_framework.compat import (timezone, parse_date, parse_datetime, + parse_time) from rest_framework.compat import BytesIO from rest_framework.compat import six from rest_framework.compat import smart_text from rest_framework.settings import api_settings +HUMANIZED_FIELD_TYPES = { + 'BooleanField': u'Boolean', + 'CharField': u'Single Character', + '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): """ True if the object is a callable that takes no arguments. @@ -62,7 +93,8 @@ def get_component(obj, attr_name): def readable_datetime_formats(formats): - format = ', '.join(formats).replace(ISO_8601, 'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HHMM|-HHMM|Z]') + format = ', '.join(formats).replace(ISO_8601, + 'YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HHMM|-HHMM|Z]') return humanize_strptime(format) @@ -71,6 +103,61 @@ def readable_date_formats(formats): 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': (field.type_name if field.type_name + else humanize_field_type(field.form_field_class)), + 'required': getattr(field, 'required', False), + 'label': field.label, + } + optional_attrs = ['read_only', 'help_text'] + for attr in optional_attrs: + if hasattr(field, attr): + humanized[attr] = getattr(field, attr) + return humanized + + +def humanize_form_fields(form): + """Return a humanized description of all the fields in a form. + + :param form: A Django form. + :return: A dictionary of {field_label: humanized description} + + """ + fields = SortedDict([(f.name, humanize_field(f)) for f in form.fields]) + return fields + + def readable_time_formats(formats): format = ', '.join(formats).replace(ISO_8601, 'hh:mm[:ss[.uuuuuu]]') return humanize_strptime(format) -- cgit v1.2.3 From fecadacab150aab48b8b84f4f0e5340ead74c287 Mon Sep 17 00:00:00 2001 From: Oscar Vilaplana Date: Sat, 18 May 2013 18:27:53 +0200 Subject: added tests for form --- rest_framework/fields.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index b23813ec..544afc98 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -135,8 +135,7 @@ def humanize_field(field): """ humanized = { - 'type': (field.type_name if field.type_name - else humanize_field_type(field.form_field_class)), + 'type': humanize_field_type(field.__class__), 'required': getattr(field, 'required', False), 'label': field.label, } @@ -154,7 +153,8 @@ def humanize_form_fields(form): :return: A dictionary of {field_label: humanized description} """ - fields = SortedDict([(f.name, humanize_field(f)) for f in form.fields]) + fields = SortedDict([(name, humanize_field(field)) + for name, field in form.fields.iteritems()]) return fields -- cgit v1.2.3 From c0f3a1c397a564ee78b3a656f14f7ff46b0d2b31 Mon Sep 17 00:00:00 2001 From: Nikolaus Schlemm Date: Sun, 19 May 2013 09:25:02 +0200 Subject: Integrated status quo of grimborg's awesome humanize_field() for exposing field metadata via OPTIONS :) --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index d6db3ebe..a215e02b 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -136,7 +136,7 @@ def humanize_field(field): humanized = { 'type': humanize_field_type(field.__class__), 'required': getattr(field, 'required', False), - 'label': field.label, + 'label': getattr(field, 'label', None), } optional_attrs = ['read_only', 'help_text'] for attr in optional_attrs: -- cgit v1.2.3 From b915c1d4d81fc459ed7c79ee5264ef7467963c3f Mon Sep 17 00:00:00 2001 From: Oscar Vilaplana Date: Sun, 19 May 2013 11:15:38 +0200 Subject: Made field label optional in OPTIONS --- rest_framework/fields.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index a215e02b..b1bbb4d4 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -136,11 +136,10 @@ def humanize_field(field): humanized = { 'type': humanize_field_type(field.__class__), 'required': getattr(field, 'required', False), - 'label': getattr(field, 'label', None), } - optional_attrs = ['read_only', 'help_text'] + optional_attrs = ['read_only', 'help_text', 'label'] for attr in optional_attrs: - if hasattr(field, attr): + if getattr(field, attr, None) is not None: humanized[attr] = getattr(field, attr) return humanized -- cgit v1.2.3 From 696c053f4fbbbb302d9b214d8daf511879256a7f Mon Sep 17 00:00:00 2001 From: Oscar Vilaplana Date: Sun, 19 May 2013 15:04:43 +0200 Subject: s/Single Character/String/ --- rest_framework/fields.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index b1bbb4d4..98768d72 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -33,7 +33,7 @@ from rest_framework.settings import api_settings HUMANIZED_FIELD_TYPES = { 'BooleanField': u'Boolean', - 'CharField': u'Single Character', + 'CharField': u'String', 'ChoiceField': u'Single Choice', 'ComboField': u'Single Choice', 'DateField': u'Date', -- cgit v1.2.3 From e80488b6192580c7a731114e58edd718d1c79120 Mon Sep 17 00:00:00 2001 From: Oscar Vilaplana Date: Sun, 19 May 2013 15:08:41 +0200 Subject: Added min_length and max_length --- rest_framework/fields.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 98768d72..cdcb0ee9 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -137,7 +137,8 @@ def humanize_field(field): 'type': humanize_field_type(field.__class__), 'required': getattr(field, 'required', False), } - optional_attrs = ['read_only', 'help_text', 'label'] + 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) -- cgit v1.2.3 From a1deb5eac7d6d00c6269d88fce1cc6818d8ec04a Mon Sep 17 00:00:00 2001 From: Oscar Vilaplana Date: Thu, 23 May 2013 08:26:55 +0200 Subject: simplified, moved field humanizing to Field. broken tests --- rest_framework/fields.py | 86 ++++++++---------------------------------------- 1 file changed, 13 insertions(+), 73 deletions(-) (limited to 'rest_framework/fields.py') diff --git a/rest_framework/fields.py b/rest_framework/fields.py index cdcb0ee9..d5a1394d 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -31,36 +31,6 @@ from rest_framework.compat import smart_text, force_text, is_non_str_iterable 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): """ True if the object is a callable that takes no arguments. @@ -102,49 +72,6 @@ def readable_date_formats(formats): 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): """Return a humanized description of all the fields in a form. @@ -274,6 +201,19 @@ class Field(object): return {'type': self.type_name} 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): """ -- cgit v1.2.3