From 14ae52a24e93063f77c6010269bf9cd3316627fe Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 8 Oct 2014 16:09:37 +0100 Subject: More gradual deprecation --- rest_framework/request.py | 16 ++++++++ rest_framework/serializers.py | 71 ++++++++++++++++++++++++++++++++++- rest_framework/utils/field_mapping.py | 22 +++++------ rest_framework/utils/model_meta.py | 4 +- 4 files changed, 99 insertions(+), 14 deletions(-) (limited to 'rest_framework') diff --git a/rest_framework/request.py b/rest_framework/request.py index d80baa70..d4352742 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -18,6 +18,7 @@ from rest_framework import HTTP_HEADER_ENCODING from rest_framework import exceptions from rest_framework.compat import BytesIO from rest_framework.settings import api_settings +import warnings def is_form_media_type(media_type): @@ -209,6 +210,11 @@ class Request(object): """ Synonym for `.query_params`, for backwards compatibility. """ + warnings.warn( + "`request.QUERY_PARAMS` is pending deprecation. Use `request.query_params` instead.", + PendingDeprecationWarning, + stacklevel=1 + ) return self._request.GET @property @@ -225,6 +231,11 @@ class Request(object): Similar to usual behaviour of `request.POST`, except that it handles arbitrary parsers, and also works on methods other than POST (eg PUT). """ + warnings.warn( + "`request.DATA` is pending deprecation. Use `request.data` instead.", + PendingDeprecationWarning, + stacklevel=1 + ) if not _hasattr(self, '_data'): self._load_data_and_files() return self._data @@ -237,6 +248,11 @@ class Request(object): Similar to usual behaviour of `request.FILES`, except that it handles arbitrary parsers, and also works on methods other than POST (eg PUT). """ + warnings.warn( + "`request.FILES` is pending deprecation. Use `request.data` instead.", + PendingDeprecationWarning, + stacklevel=1 + ) if not _hasattr(self, '_files'): self._load_data_and_files() return self._files diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 8513428c..9fcbcba7 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -25,6 +25,7 @@ from rest_framework.utils.field_mapping import ( from rest_framework.validators import UniqueTogetherValidator import copy import inspect +import warnings # Note: We do the following so that users of the framework can use this style: # @@ -517,12 +518,24 @@ class ModelSerializer(Serializer): depth = getattr(self.Meta, 'depth', 0) extra_kwargs = getattr(self.Meta, 'extra_kwargs', {}) + extra_kwargs = self._include_additional_options(extra_kwargs) + # Retrieve metadata about fields & relationships on the model class. info = model_meta.get_field_info(model) # Use the default set of fields if none is supplied explicitly. if fields is None: fields = self._get_default_field_names(declared_fields, info) + exclude = getattr(self.Meta, 'exclude', None) + if exclude is not None: + warnings.warn( + "The `Meta.exclude` option is pending deprecation. " + "Use the explicit `Meta.fields` instead.", + PendingDeprecationWarning, + stacklevel=3 + ) + for field_name in exclude: + fields.remove(field_name) for field_name in fields: if field_name in declared_fields: @@ -589,13 +602,69 @@ class ModelSerializer(Serializer): ) # Populate any kwargs defined in `Meta.extra_kwargs` - kwargs.update(extra_kwargs.get(field_name, {})) + extras = extra_kwargs.get(field_name, {}) + if extras.get('read_only', False): + for attr in [ + 'required', 'default', 'allow_blank', 'allow_null', + 'min_length', 'max_length', 'min_value', 'max_value', + 'validators' + ]: + kwargs.pop(attr, None) + kwargs.update(extras) # Create the serializer field. ret[field_name] = field_cls(**kwargs) return ret + def _include_additional_options(self, extra_kwargs): + read_only_fields = getattr(self.Meta, 'read_only_fields', None) + if read_only_fields is not None: + for field_name in read_only_fields: + kwargs = extra_kwargs.get(field_name, {}) + kwargs['read_only'] = True + extra_kwargs[field_name] = kwargs + + # These are all pending deprecation. + write_only_fields = getattr(self.Meta, 'write_only_fields', None) + if write_only_fields is not None: + warnings.warn( + "The `Meta.write_only_fields` option is pending deprecation. " + "Use `Meta.extra_kwargs={: {'write_only': True}}` instead.", + PendingDeprecationWarning, + stacklevel=3 + ) + for field_name in write_only_fields: + kwargs = extra_kwargs.get(field_name, {}) + kwargs['write_only'] = True + extra_kwargs[field_name] = kwargs + + view_name = getattr(self.Meta, 'view_name', None) + if view_name is not None: + warnings.warn( + "The `Meta.view_name` option is pending deprecation. " + "Use `Meta.extra_kwargs={'url': {'view_name': ...}}` instead.", + PendingDeprecationWarning, + stacklevel=3 + ) + kwargs = extra_kwargs.get(field_name, {}) + kwargs['view_name'] = view_name + extra_kwargs[api_settings.URL_FIELD_NAME] = kwargs + + lookup_field = getattr(self.Meta, 'lookup_field', None) + if lookup_field is not None: + warnings.warn( + "The `Meta.lookup_field` option is pending deprecation. " + "Use `Meta.extra_kwargs={'url': {'lookup_field': ...}}` instead.", + PendingDeprecationWarning, + stacklevel=3 + ) + kwargs = extra_kwargs.get(field_name, {}) + kwargs['lookup_field'] = lookup_field + extra_kwargs[api_settings.URL_FIELD_NAME] = kwargs + + return extra_kwargs + def _get_default_field_names(self, declared_fields, model_info): return ( [model_info.pk.name] + diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index fd6da699..6db37146 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -71,6 +71,17 @@ def get_field_kwargs(field_name, model_field): if model_field.help_text: kwargs['help_text'] = model_field.help_text + max_digits = getattr(model_field, 'max_digits', None) + if max_digits is not None: + kwargs['max_digits'] = max_digits + + decimal_places = getattr(model_field, 'decimal_places', None) + if decimal_places is not None: + kwargs['decimal_places'] = decimal_places + + if isinstance(model_field, models.TextField): + kwargs['style'] = {'type': 'textarea'} + if isinstance(model_field, models.AutoField) or not model_field.editable: # If this field is read-only, then return early. # Further keyword arguments are not valid. @@ -86,9 +97,6 @@ def get_field_kwargs(field_name, model_field): kwargs['choices'] = model_field.flatchoices return kwargs - if isinstance(model_field, models.TextField): - kwargs['style'] = {'type': 'textarea'} - if model_field.null and not isinstance(model_field, models.NullBooleanField): kwargs['allow_null'] = True @@ -171,14 +179,6 @@ def get_field_kwargs(field_name, model_field): validator = UniqueValidator(queryset=model_field.model._default_manager) validator_kwarg.append(validator) - max_digits = getattr(model_field, 'max_digits', None) - if max_digits is not None: - kwargs['max_digits'] = max_digits - - decimal_places = getattr(model_field, 'decimal_places', None) - if decimal_places is not None: - kwargs['decimal_places'] = decimal_places - if validator_kwarg: kwargs['validators'] = validator_kwarg diff --git a/rest_framework/utils/model_meta.py b/rest_framework/utils/model_meta.py index b6c41174..7a95bcdd 100644 --- a/rest_framework/utils/model_meta.py +++ b/rest_framework/utils/model_meta.py @@ -107,8 +107,8 @@ def get_field_info(model): related=relation.model, to_many=True, has_through_model=( - hasattr(relation.field.rel, 'through') and - not relation.field.rel.through._meta.auto_created + (getattr(relation.field.rel, 'through', None) is not None) + and not relation.field.rel.through._meta.auto_created ) ) -- cgit v1.2.3