From 34d2ad4faa59050c4b9afba19ba34db9a58fbbd2 Mon Sep 17 00:00:00 2001 From: John Parton Date: Fri, 21 May 2021 13:07:48 -0500 Subject: [PATCH 01/10] Propagate 'default' from model_field to serializer field Fix #7469. Co-authored-by: Nikhil Benesch --- rest_framework/utils/field_mapping.py | 3 +++ tests/test_model_serializer.py | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index fc63f96fe0..fbb0486288 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -127,6 +127,9 @@ def get_field_kwargs(field_name, model_field): kwargs['read_only'] = True return kwargs + if model_field.has_default(): + kwargs['default'] = model_field.default + if model_field.has_default() or model_field.blank or model_field.null: kwargs['required'] = False diff --git a/tests/test_model_serializer.py b/tests/test_model_serializer.py index c5ac888f55..94ae6022e0 100644 --- a/tests/test_model_serializer.py +++ b/tests/test_model_serializer.py @@ -173,7 +173,7 @@ class Meta: TestSerializer(): auto_field = IntegerField(read_only=True) big_integer_field = IntegerField() - boolean_field = BooleanField(required=False) + boolean_field = BooleanField(default=False, required=False) char_field = CharField(max_length=100) comma_separated_integer_field = CharField(max_length=100, validators=[]) date_field = DateField() @@ -182,7 +182,7 @@ class Meta: email_field = EmailField(max_length=100) float_field = FloatField() integer_field = IntegerField() - null_boolean_field = BooleanField(allow_null=True, required=False) + null_boolean_field = BooleanField(allow_null=True, default=False, required=False) positive_integer_field = IntegerField() positive_small_integer_field = IntegerField() slug_field = SlugField(allow_unicode=False, max_length=100) @@ -210,7 +210,7 @@ class Meta: length_limit_field = CharField(max_length=12, min_length=3) blank_field = CharField(allow_blank=True, max_length=10, required=False) null_field = IntegerField(allow_null=True, required=False) - default_field = IntegerField(required=False) + default_field = IntegerField(default=0, required=False) descriptive_field = IntegerField(help_text='Some help text', label='A label') choices_field = ChoiceField(choices=(('red', 'Red'), ('blue', 'Blue'), ('green', 'Green'))) text_choices_field = ChoiceField(choices=(('red', 'Red'), ('blue', 'Blue'), ('green', 'Green'))) From 728fdbe13c7ac859727c2ab106d3cb20cf8444c0 Mon Sep 17 00:00:00 2001 From: Rizwan Shaikh Date: Tue, 27 Jun 2023 22:55:52 +0530 Subject: [PATCH 02/10] updated field default on serializer according to openapi generation and added that to options action response --- rest_framework/metadata.py | 4 + rest_framework/utils/field_mapping.py | 3 +- tests/test_metadata.py | 129 ++++++++++++++++++++++++++ 3 files changed, 135 insertions(+), 1 deletion(-) diff --git a/rest_framework/metadata.py b/rest_framework/metadata.py index 364ca5b14d..fd0f4e163d 100644 --- a/rest_framework/metadata.py +++ b/rest_framework/metadata.py @@ -11,6 +11,7 @@ from django.utils.encoding import force_str from rest_framework import exceptions, serializers +from rest_framework.fields import empty from rest_framework.request import clone_request from rest_framework.utils.field_mapping import ClassLookupDict @@ -149,4 +150,7 @@ def get_field_info(self, field): for choice_value, choice_name in field.choices.items() ] + if getattr(field, 'default', None) and field.default != empty and not callable(field.default): + field_info['default'] = field.default + return field_info diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index fbb0486288..30bb65e0cf 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -9,6 +9,7 @@ from django.utils.text import capfirst from rest_framework.compat import postgres_fields +from rest_framework.fields import empty from rest_framework.validators import UniqueValidator NUMERIC_FIELD_TYPES = ( @@ -127,7 +128,7 @@ def get_field_kwargs(field_name, model_field): kwargs['read_only'] = True return kwargs - if model_field.has_default(): + if model_field.default is not None and model_field.default != empty and not callable(model_field.default): kwargs['default'] = model_field.default if model_field.has_default() or model_field.blank or model_field.null: diff --git a/tests/test_metadata.py b/tests/test_metadata.py index 1bdc8697c4..387b9ecded 100644 --- a/tests/test_metadata.py +++ b/tests/test_metadata.py @@ -184,6 +184,135 @@ def get_serializer(self): assert response.status_code == status.HTTP_200_OK assert response.data == expected + def test_actions_with_default(self): + """ + On generic views OPTIONS should return an 'actions' key with metadata + on the fields with default that may be supplied to PUT and POST requests. + """ + class NestedField(serializers.Serializer): + a = serializers.IntegerField(default=2) + b = serializers.IntegerField() + + class ExampleSerializer(serializers.Serializer): + choice_field = serializers.ChoiceField(['red', 'green', 'blue'], default='red') + integer_field = serializers.IntegerField( + min_value=1, max_value=1000, default=1 + ) + char_field = serializers.CharField( + min_length=3, max_length=40, default="example" + ) + list_field = serializers.ListField( + child=serializers.ListField( + child=serializers.IntegerField(default=1) + ) + ) + nested_field = NestedField() + uuid_field = serializers.UUIDField(label="UUID field") + + class ExampleView(views.APIView): + """Example view.""" + def post(self, request): + pass + + def get_serializer(self): + return ExampleSerializer() + + view = ExampleView.as_view() + response = view(request=request) + expected = { + 'name': 'Example', + 'description': 'Example view.', + 'renders': [ + 'application/json', + 'text/html' + ], + 'parses': [ + 'application/json', + 'application/x-www-form-urlencoded', + 'multipart/form-data' + ], + 'actions': { + 'POST': { + 'choice_field': { + 'type': 'choice', + 'required': False, + 'read_only': False, + 'label': 'Choice field', + "choices": [ + {'value': 'red', 'display_name': 'red'}, + {'value': 'green', 'display_name': 'green'}, + {'value': 'blue', 'display_name': 'blue'} + ], + 'default': 'red' + }, + 'integer_field': { + 'type': 'integer', + 'required': False, + 'read_only': False, + 'label': 'Integer field', + 'min_value': 1, + 'max_value': 1000, + 'default': 1 + }, + 'char_field': { + 'type': 'string', + 'required': False, + 'read_only': False, + 'label': 'Char field', + 'min_length': 3, + 'max_length': 40, + 'default': 'example' + }, + 'list_field': { + 'type': 'list', + 'required': True, + 'read_only': False, + 'label': 'List field', + 'child': { + 'type': 'list', + 'required': True, + 'read_only': False, + 'child': { + 'type': 'integer', + 'required': False, + 'read_only': False, + 'default': 1 + } + } + }, + 'nested_field': { + 'type': 'nested object', + 'required': True, + 'read_only': False, + 'label': 'Nested field', + 'children': { + 'a': { + 'type': 'integer', + 'required': False, + 'read_only': False, + 'label': 'A', + 'default': 2 + }, + 'b': { + 'type': 'integer', + 'required': True, + 'read_only': False, + 'label': 'B' + } + } + }, + 'uuid_field': { + 'type': 'string', + 'required': True, + 'read_only': False, + 'label': 'UUID field' + } + } + } + } + assert response.status_code == status.HTTP_200_OK + assert response.data == expected + def test_global_permissions(self): """ If a user does not have global permissions on an action, then any From 2cc065f9f7fd28f17b1e9843ebdeec9afba58819 Mon Sep 17 00:00:00 2001 From: Rizwan Shaikh Date: Mon, 31 Jul 2023 23:31:24 +0530 Subject: [PATCH 03/10] added notes regarding default value propagation from model to serializer field --- docs/api-guide/fields.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 4ac3e3c31a..07c2c68be9 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -68,6 +68,15 @@ When serializing the instance, default will be used if the object attribute or d Note that setting a `default` value implies that the field is not required. Including both the `default` and `required` keyword arguments is invalid and will raise an error. +Notes Regarding default value propagation from model to serializer: + +all the default values of model will be pass as default to serializer and to the options method. + +if the default is callable then it is propagated in serializer which is evaluated at each time but +not in options method. + +if the value for given field is not given then default value will be present in serializer also avaliable in serializer's methods.Specified validation on given field will be evaluted on default value as that field will be present in serializer. + ### `allow_null` Normally an error will be raised if `None` is passed to a serializer field. Set this keyword argument to `True` if `None` should be considered a valid value. From 150cc7cfa71a22baacc345520f64b708eb914e2e Mon Sep 17 00:00:00 2001 From: Rizwan Shaikh Date: Mon, 31 Jul 2023 23:38:33 +0530 Subject: [PATCH 04/10] updated note --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 07c2c68be9..2852c0ec1b 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -68,7 +68,7 @@ When serializing the instance, default will be used if the object attribute or d Note that setting a `default` value implies that the field is not required. Including both the `default` and `required` keyword arguments is invalid and will raise an error. -Notes Regarding default value propagation from model to serializer: +Notes regarding default value propagation from model to serializer: all the default values of model will be pass as default to serializer and to the options method. From 9a2bae6894836dafb7b6d390300a2921e975927b Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Wed, 2 Aug 2023 11:28:09 +0600 Subject: [PATCH 05/10] Update docs/api-guide/fields.md --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 2852c0ec1b..a907ef485d 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -75,7 +75,7 @@ all the default values of model will be pass as default to serializer and to the if the default is callable then it is propagated in serializer which is evaluated at each time but not in options method. -if the value for given field is not given then default value will be present in serializer also avaliable in serializer's methods.Specified validation on given field will be evaluted on default value as that field will be present in serializer. +If the value for given field is not given then default value will be present in the serializer and available in serializer's methods. Specified validation on given field will be evaluated on default value as that field will be present in the serializer. ### `allow_null` From 268b30ae9143ee01c20398b7522100995bdcbfa9 Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Wed, 2 Aug 2023 11:28:34 +0600 Subject: [PATCH 06/10] Update docs/api-guide/fields.md --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index a907ef485d..56a79483a3 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -70,7 +70,7 @@ Note that setting a `default` value implies that the field is not required. Incl Notes regarding default value propagation from model to serializer: -all the default values of model will be pass as default to serializer and to the options method. +all the default values of model will pass as default to the serializer and to the options method. if the default is callable then it is propagated in serializer which is evaluated at each time but not in options method. From 053c39200bd058916d1b4a60a524b60a35fc46a5 Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Sat, 5 Aug 2023 10:47:36 +0600 Subject: [PATCH 07/10] Update docs/api-guide/fields.md --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 56a79483a3..efc07df478 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -70,7 +70,7 @@ Note that setting a `default` value implies that the field is not required. Incl Notes regarding default value propagation from model to serializer: -all the default values of model will pass as default to the serializer and to the options method. +All the default values from model will pass as default to the serializer and the options method. if the default is callable then it is propagated in serializer which is evaluated at each time but not in options method. From c9dfe68af8cbbfb08d91f687bc759ccc58abc19c Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Sat, 5 Aug 2023 10:48:05 +0600 Subject: [PATCH 08/10] Update docs/api-guide/fields.md --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index efc07df478..89130a876a 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -72,7 +72,7 @@ Notes regarding default value propagation from model to serializer: All the default values from model will pass as default to the serializer and the options method. -if the default is callable then it is propagated in serializer which is evaluated at each time but +If the default is callable then it will be propagated in serializer which is evaluated at each time but not in options method. If the value for given field is not given then default value will be present in the serializer and available in serializer's methods. Specified validation on given field will be evaluated on default value as that field will be present in the serializer. From ada14ece805b55b790881502ce89b8c65cd7ecc8 Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Mon, 7 Aug 2023 11:57:27 +0600 Subject: [PATCH 09/10] Update docs/api-guide/fields.md --- docs/api-guide/fields.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 89130a876a..7b6d8c90df 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -72,7 +72,7 @@ Notes regarding default value propagation from model to serializer: All the default values from model will pass as default to the serializer and the options method. -If the default is callable then it will be propagated in serializer which is evaluated at each time but +If the default is callable then it will be propagated to & evaluated every time in the serializer but not in options method. not in options method. If the value for given field is not given then default value will be present in the serializer and available in serializer's methods. Specified validation on given field will be evaluated on default value as that field will be present in the serializer. From 660aad5b69889a43ceba19f16c6e61621a9f3910 Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Mon, 7 Aug 2023 11:57:35 +0600 Subject: [PATCH 10/10] Update docs/api-guide/fields.md --- docs/api-guide/fields.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/api-guide/fields.md b/docs/api-guide/fields.md index 7b6d8c90df..7c27162187 100644 --- a/docs/api-guide/fields.md +++ b/docs/api-guide/fields.md @@ -73,7 +73,6 @@ Notes regarding default value propagation from model to serializer: All the default values from model will pass as default to the serializer and the options method. If the default is callable then it will be propagated to & evaluated every time in the serializer but not in options method. -not in options method. If the value for given field is not given then default value will be present in the serializer and available in serializer's methods. Specified validation on given field will be evaluated on default value as that field will be present in the serializer.