From 5b7e4af0d657a575cb15eea85a63a7100c636085 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 18 Sep 2014 11:20:56 +0100 Subject: get_base_field() refactor --- rest_framework/utils/field_mapping.py | 215 ++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 rest_framework/utils/field_mapping.py (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py new file mode 100644 index 00000000..be72e444 --- /dev/null +++ b/rest_framework/utils/field_mapping.py @@ -0,0 +1,215 @@ +""" +Helper functions for mapping model fields to a dictionary of default +keyword arguments that should be used for their equivelent serializer fields. +""" +from django.core import validators +from django.db import models +from django.utils.text import capfirst +from rest_framework.compat import clean_manytomany_helptext +import inspect + + +def lookup_class(mapping, instance): + """ + Takes a dictionary with classes as keys, and an object. + Traverses the object's inheritance hierarchy in method + resolution order, and returns the first matching value + from the dictionary or raises a KeyError if nothing matches. + """ + for cls in inspect.getmro(instance.__class__): + if cls in mapping: + return mapping[cls] + raise KeyError('Class %s not found in lookup.', cls.__name__) + + +def needs_label(model_field, field_name): + """ + Returns `True` if the label based on the model's verbose name + is not equal to the default label it would have based on it's field name. + """ + default_label = field_name.replace('_', ' ').capitalize() + return capfirst(model_field.verbose_name) != default_label + + +def get_detail_view_name(model): + """ + Given a model class, return the view name to use for URL relationships + that refer to instances of the model. + """ + return '%(model_name)s-detail' % { + 'app_label': model._meta.app_label, + 'model_name': model._meta.object_name.lower() + } + + +def get_field_kwargs(field_name, model_field): + """ + Creates a default instance of a basic non-relational field. + """ + kwargs = {} + validator_kwarg = model_field.validators + + if model_field.null or model_field.blank: + kwargs['required'] = False + + if model_field.verbose_name and needs_label(model_field, field_name): + kwargs['label'] = capfirst(model_field.verbose_name) + + if model_field.help_text: + kwargs['help_text'] = model_field.help_text + + if isinstance(model_field, models.AutoField) or not model_field.editable: + kwargs['read_only'] = True + # Read only implies that the field is not required. + # We have a cleaner repr on the instance if we don't set it. + kwargs.pop('required', None) + + if model_field.has_default(): + kwargs['default'] = model_field.get_default() + # Having a default implies that the field is not required. + # We have a cleaner repr on the instance if we don't set it. + kwargs.pop('required', None) + + if model_field.flatchoices: + # If this model field contains choices, then return now, + # any further keyword arguments are not valid. + kwargs['choices'] = model_field.flatchoices + return kwargs + + # Ensure that max_length is passed explicitly as a keyword arg, + # rather than as a validator. + max_length = getattr(model_field, 'max_length', None) + if max_length is not None: + kwargs['max_length'] = max_length + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MaxLengthValidator) + ] + + # Ensure that min_length is passed explicitly as a keyword arg, + # rather than as a validator. + min_length = getattr(model_field, 'min_length', None) + if min_length is not None: + kwargs['min_length'] = min_length + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MinLengthValidator) + ] + + # Ensure that max_value is passed explicitly as a keyword arg, + # rather than as a validator. + max_value = next(( + validator.limit_value for validator in validator_kwarg + if isinstance(validator, validators.MaxValueValidator) + ), None) + if max_value is not None: + kwargs['max_value'] = max_value + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MaxValueValidator) + ] + + # Ensure that max_value is passed explicitly as a keyword arg, + # rather than as a validator. + min_value = next(( + validator.limit_value for validator in validator_kwarg + if isinstance(validator, validators.MinValueValidator) + ), None) + if min_value is not None: + kwargs['min_value'] = min_value + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.MinValueValidator) + ] + + # URLField does not need to include the URLValidator argument, + # as it is explicitly added in. + if isinstance(model_field, models.URLField): + validator_kwarg = [ + validator for validator in validator_kwarg + if not isinstance(validator, validators.URLValidator) + ] + + # EmailField does not need to include the validate_email argument, + # as it is explicitly added in. + if isinstance(model_field, models.EmailField): + validator_kwarg = [ + validator for validator in validator_kwarg + if validator is not validators.validate_email + ] + + # SlugField do not need to include the 'validate_slug' argument, + if isinstance(model_field, models.SlugField): + validator_kwarg = [ + validator for validator in validator_kwarg + if validator is not validators.validate_slug + ] + + 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.BooleanField): + # models.BooleanField has `blank=True`, but *is* actually + # required *unless* a default is provided. + # Also note that Django<1.6 uses `default=False` for + # models.BooleanField, but Django>=1.6 uses `default=None`. + kwargs.pop('required', None) + + if validator_kwarg: + kwargs['validators'] = validator_kwarg + + # The following will only be used by ModelField classes. + # Gets removed for everything else. + kwargs['model_field'] = model_field + + return kwargs + + +def get_relation_kwargs(field_name, relation_info): + """ + Creates a default instance of a flat relational field. + """ + model_field, related_model, to_many, has_through_model = relation_info + kwargs = { + 'queryset': related_model._default_manager, + 'view_name': get_detail_view_name(related_model) + } + + if to_many: + kwargs['many'] = True + + if has_through_model: + kwargs['read_only'] = True + kwargs.pop('queryset', None) + + if model_field: + if model_field.null or model_field.blank: + kwargs['required'] = False + if model_field.verbose_name and needs_label(model_field, field_name): + kwargs['label'] = capfirst(model_field.verbose_name) + if not model_field.editable: + kwargs['read_only'] = True + kwargs.pop('queryset', None) + help_text = clean_manytomany_helptext(model_field.help_text) + if help_text: + kwargs['help_text'] = help_text + + return kwargs + + +def get_nested_relation_kwargs(relation_info): + kwargs = {'read_only': True} + if relation_info.to_many: + kwargs['many'] = True + return kwargs + + +def get_url_kwargs(model_field): + return { + 'view_name': get_detail_view_name(model_field) + } -- cgit v1.2.3 From f22d0afc3dfc7478e084d1d6ed6b53f71641dec6 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 23 Sep 2014 14:15:00 +0100 Subject: Tests for field choices --- rest_framework/utils/field_mapping.py | 58 ++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 28 deletions(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index be72e444..1c718ccb 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -49,8 +49,9 @@ def get_field_kwargs(field_name, model_field): kwargs = {} validator_kwarg = model_field.validators - if model_field.null or model_field.blank: - kwargs['required'] = False + # The following will only be used by ModelField classes. + # Gets removed for everything else. + kwargs['model_field'] = model_field if model_field.verbose_name and needs_label(model_field, field_name): kwargs['label'] = capfirst(model_field.verbose_name) @@ -59,23 +60,26 @@ def get_field_kwargs(field_name, model_field): kwargs['help_text'] = model_field.help_text 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. kwargs['read_only'] = True - # Read only implies that the field is not required. - # We have a cleaner repr on the instance if we don't set it. - kwargs.pop('required', None) + return kwargs if model_field.has_default(): - kwargs['default'] = model_field.get_default() - # Having a default implies that the field is not required. - # We have a cleaner repr on the instance if we don't set it. - kwargs.pop('required', None) + kwargs['required'] = False if model_field.flatchoices: - # If this model field contains choices, then return now, - # any further keyword arguments are not valid. + # If this model field contains choices, then return early. + # Further keyword arguments are not valid. kwargs['choices'] = model_field.flatchoices return kwargs + if model_field.null: + kwargs['allow_null'] = True + + if model_field.blank: + kwargs['allow_blank'] = True + # Ensure that max_length is passed explicitly as a keyword arg, # rather than as a validator. max_length = getattr(model_field, 'max_length', None) @@ -88,7 +92,10 @@ def get_field_kwargs(field_name, model_field): # Ensure that min_length is passed explicitly as a keyword arg, # rather than as a validator. - min_length = getattr(model_field, 'min_length', None) + min_length = next(( + validator.limit_value for validator in validator_kwarg + if isinstance(validator, validators.MinLengthValidator) + ), None) if min_length is not None: kwargs['min_length'] = min_length validator_kwarg = [ @@ -153,20 +160,9 @@ def get_field_kwargs(field_name, model_field): if decimal_places is not None: kwargs['decimal_places'] = decimal_places - if isinstance(model_field, models.BooleanField): - # models.BooleanField has `blank=True`, but *is* actually - # required *unless* a default is provided. - # Also note that Django<1.6 uses `default=False` for - # models.BooleanField, but Django>=1.6 uses `default=None`. - kwargs.pop('required', None) - if validator_kwarg: kwargs['validators'] = validator_kwarg - # The following will only be used by ModelField classes. - # Gets removed for everything else. - kwargs['model_field'] = model_field - return kwargs @@ -188,16 +184,22 @@ def get_relation_kwargs(field_name, relation_info): kwargs.pop('queryset', None) if model_field: - if model_field.null or model_field.blank: - kwargs['required'] = False if model_field.verbose_name and needs_label(model_field, field_name): kwargs['label'] = capfirst(model_field.verbose_name) - if not model_field.editable: - kwargs['read_only'] = True - kwargs.pop('queryset', None) help_text = clean_manytomany_helptext(model_field.help_text) if help_text: kwargs['help_text'] = help_text + if not model_field.editable: + kwargs['read_only'] = True + kwargs.pop('queryset', None) + if kwargs.get('read_only', False): + # If this field is read-only, then return early. + # No further keyword arguments are valid. + return kwargs + if model_field.has_default(): + kwargs['required'] = False + if model_field.null: + kwargs['allow_null'] = True return kwargs -- cgit v1.2.3 From 0404f09a7e69f533038d47ca25caad90c0c2659f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 23 Sep 2014 14:30:17 +0100 Subject: NullBooleanField --- rest_framework/utils/field_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 1c718ccb..c208afdc 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -74,7 +74,7 @@ def get_field_kwargs(field_name, model_field): kwargs['choices'] = model_field.flatchoices return kwargs - if model_field.null: + if model_field.null and not isinstance(model_field, models.NullBooleanField): kwargs['allow_null'] = True if model_field.blank: -- cgit v1.2.3 From f4b1dcb167be0bbdaae2cc2a92f651536896dc16 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 24 Sep 2014 14:09:49 +0100 Subject: OPTIONS support --- rest_framework/utils/field_mapping.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index c208afdc..c3794083 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -9,17 +9,21 @@ from rest_framework.compat import clean_manytomany_helptext import inspect -def lookup_class(mapping, instance): +class ClassLookupDict(object): """ - Takes a dictionary with classes as keys, and an object. - Traverses the object's inheritance hierarchy in method - resolution order, and returns the first matching value + Takes a dictionary with classes as keys. + Lookups against this object will traverses the object's inheritance + hierarchy in method resolution order, and returns the first matching value from the dictionary or raises a KeyError if nothing matches. """ - for cls in inspect.getmro(instance.__class__): - if cls in mapping: - return mapping[cls] - raise KeyError('Class %s not found in lookup.', cls.__name__) + def __init__(self, mapping): + self.mapping = mapping + + def __getitem__(self, key): + for cls in inspect.getmro(key.__class__): + if cls in self.mapping: + return self.mapping[cls] + raise KeyError('Class %s not found in lookup.', cls.__name__) def needs_label(model_field, field_name): -- cgit v1.2.3 From 43fd5a873051c99600386c1fdc9fa368edeb6eda Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 29 Sep 2014 09:24:03 +0100 Subject: Uniqueness validation --- rest_framework/utils/field_mapping.py | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index c3794083..cf9d910a 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -6,6 +6,7 @@ from django.core import validators from django.db import models from django.utils.text import capfirst from rest_framework.compat import clean_manytomany_helptext +from rest_framework.validators import UniqueValidator import inspect @@ -156,6 +157,10 @@ def get_field_kwargs(field_name, model_field): if validator is not validators.validate_slug ] + if getattr(model_field, 'unique', False): + 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 -- cgit v1.2.3 From c171fa21ac62538331755524057d2435f33ec8a5 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Wed, 1 Oct 2014 19:44:46 +0100 Subject: First pass at HTML form rendering --- rest_framework/utils/field_mapping.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index cf9d910a..b4d33e39 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -79,6 +79,9 @@ 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 -- cgit v1.2.3 From df7b6fcf58417fd95e49655eb140b387899b1ceb Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 2 Oct 2014 16:24:24 +0100 Subject: First pass on incorperating the form rendering into the browsable API --- rest_framework/utils/field_mapping.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index b4d33e39..30fae370 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -21,7 +21,14 @@ class ClassLookupDict(object): self.mapping = mapping def __getitem__(self, key): - for cls in inspect.getmro(key.__class__): + if hasattr(key, '_proxy_class'): + # Deal with proxy classes. Ie. BoundField behaves as if it + # is a Field instance when using ClassLookupDict. + base_class = key._proxy_class + else: + base_class = key.__class__ + + for cls in inspect.getmro(base_class): if cls in self.mapping: return self.mapping[cls] raise KeyError('Class %s not found in lookup.', cls.__name__) -- cgit v1.2.3 From 6bfed6f8525a49fc50df7143ac2d492528b8f2ac Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 7 Oct 2014 17:04:53 +0100 Subject: Enforce uniqueness validation for relational fields --- rest_framework/utils/field_mapping.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 30fae370..fd6da699 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -219,6 +219,9 @@ def get_relation_kwargs(field_name, relation_info): kwargs['required'] = False if model_field.null: kwargs['allow_null'] = True + if getattr(model_field, 'unique', False): + validator = UniqueValidator(queryset=model_field.model._default_manager) + kwargs['validators'] = [validator] return kwargs -- cgit v1.2.3 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/utils/field_mapping.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'rest_framework/utils/field_mapping.py') 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 -- cgit v1.2.3 From e399140031a0738a054f5f07e42ef7208f9e45f4 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 7 Nov 2014 10:51:08 +0000 Subject: Minor tweaks --- rest_framework/utils/field_mapping.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 6db37146..24639085 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -219,9 +219,11 @@ def get_relation_kwargs(field_name, relation_info): kwargs['required'] = False if model_field.null: kwargs['allow_null'] = True + if model_field.validators: + kwargs['validators'] = model_field.validators if getattr(model_field, 'unique', False): validator = UniqueValidator(queryset=model_field.model._default_manager) - kwargs['validators'] = [validator] + kwargs['validators'] = kwargs.get('validators', []) + [validator] return kwargs -- cgit v1.2.3 From ea98de9b889173235a908ee2ce5a2aba5d8223c7 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 13 Nov 2014 19:28:57 +0000 Subject: Model fields with .blank or .null now map to required=False. Closes #2017. Closes #2021. --- rest_framework/utils/field_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 24639085..ce339971 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -88,7 +88,7 @@ def get_field_kwargs(field_name, model_field): kwargs['read_only'] = True return kwargs - if model_field.has_default(): + if model_field.has_default() or model_field.blank or model_field.null: kwargs['required'] = False if model_field.flatchoices: -- cgit v1.2.3 From 4e035184384db8ed1227fdcb1dad2ea6ddb1cf68 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Thu, 13 Nov 2014 23:30:42 +0000 Subject: required=False for nullable relationships --- rest_framework/utils/field_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index ce339971..9c187176 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -215,7 +215,7 @@ def get_relation_kwargs(field_name, relation_info): # If this field is read-only, then return early. # No further keyword arguments are valid. return kwargs - if model_field.has_default(): + if model_field.has_default() or model_field.null: kwargs['required'] = False if model_field.null: kwargs['allow_null'] = True -- cgit v1.2.3 From afe7ed9333e37384f8ddc57e891da9632c8714c3 Mon Sep 17 00:00:00 2001 From: José Padilla Date: Tue, 9 Dec 2014 09:25:06 -0400 Subject: Add allow_blank for ChoiceField #2184 This makes a ChoiceField optional in HTML if model field has `blank=True` set.--- rest_framework/utils/field_mapping.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 9c187176..86ceff31 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -91,18 +91,18 @@ def get_field_kwargs(field_name, model_field): if model_field.has_default() or model_field.blank or model_field.null: kwargs['required'] = False - if model_field.flatchoices: - # If this model field contains choices, then return early. - # Further keyword arguments are not valid. - kwargs['choices'] = model_field.flatchoices - return kwargs - if model_field.null and not isinstance(model_field, models.NullBooleanField): kwargs['allow_null'] = True if model_field.blank: kwargs['allow_blank'] = True + if model_field.flatchoices: + # If this model field contains choices, then return early. + # Further keyword arguments are not valid. + kwargs['choices'] = model_field.flatchoices + return kwargs + # Ensure that max_length is passed explicitly as a keyword arg, # rather than as a validator. max_length = getattr(model_field, 'max_length', None) -- cgit v1.2.3 From 7d70e56ce378a7876a0fd7f29b52a492e46053b9 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Tue, 9 Dec 2014 16:25:10 +0000 Subject: Copy model field validators, don't reuse the same list. --- rest_framework/utils/field_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index 86ceff31..fca97b4b 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -59,7 +59,7 @@ def get_field_kwargs(field_name, model_field): Creates a default instance of a basic non-relational field. """ kwargs = {} - validator_kwarg = model_field.validators + validator_kwarg = list(model_field.validators) # The following will only be used by ModelField classes. # Gets removed for everything else. -- cgit v1.2.3 From 6c5ff712783ae7e6edebb52508f1d43249f1aa00 Mon Sep 17 00:00:00 2001 From: Remi Paulmier Date: Mon, 22 Dec 2014 18:05:07 +0100 Subject: fix the way to use textarea rather than input with models.TextField --- rest_framework/utils/field_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index fca97b4b..b16e9df0 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -80,7 +80,7 @@ def get_field_kwargs(field_name, model_field): kwargs['decimal_places'] = decimal_places if isinstance(model_field, models.TextField): - kwargs['style'] = {'type': 'textarea'} + kwargs['style'] = {'base_template': 'textarea.html'} if isinstance(model_field, models.AutoField) or not model_field.editable: # If this field is read-only, then return early. -- cgit v1.2.3 From ef2eff2abac64ffbed621bb9a72a2229841a1db1 Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Sun, 28 Dec 2014 11:07:38 +0000 Subject: Only pass max_length for CharField. Closes #2317. --- rest_framework/utils/field_mapping.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index b16e9df0..b2f4dd80 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -106,7 +106,7 @@ def get_field_kwargs(field_name, model_field): # Ensure that max_length is passed explicitly as a keyword arg, # rather than as a validator. max_length = getattr(model_field, 'max_length', None) - if max_length is not None: + if max_length is not None and isinstance(model_field, models.CharField): kwargs['max_length'] = max_length validator_kwarg = [ validator for validator in validator_kwarg -- cgit v1.2.3 From 8cf37449715c32c4a692667814466c7f32e8734f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Mon, 5 Jan 2015 10:52:18 +0000 Subject: Ensure no invalid min_length/min_value/max_value arguments. Closes #2369. --- rest_framework/utils/field_mapping.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index b2f4dd80..cba40d31 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -10,6 +10,11 @@ from rest_framework.validators import UniqueValidator import inspect +NUMERIC_FIELD_TYPES = ( + models.IntegerField, models.FloatField, models.DecimalField +) + + class ClassLookupDict(object): """ Takes a dictionary with classes as keys. @@ -119,7 +124,7 @@ def get_field_kwargs(field_name, model_field): validator.limit_value for validator in validator_kwarg if isinstance(validator, validators.MinLengthValidator) ), None) - if min_length is not None: + if min_length is not None and isinstance(model_field, models.CharField): kwargs['min_length'] = min_length validator_kwarg = [ validator for validator in validator_kwarg @@ -132,7 +137,7 @@ def get_field_kwargs(field_name, model_field): validator.limit_value for validator in validator_kwarg if isinstance(validator, validators.MaxValueValidator) ), None) - if max_value is not None: + if max_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES): kwargs['max_value'] = max_value validator_kwarg = [ validator for validator in validator_kwarg @@ -145,7 +150,7 @@ def get_field_kwargs(field_name, model_field): validator.limit_value for validator in validator_kwarg if isinstance(validator, validators.MinValueValidator) ), None) - if min_value is not None: + if min_value is not None and isinstance(model_field, NUMERIC_FIELD_TYPES): kwargs['min_value'] = min_value validator_kwarg = [ validator for validator in validator_kwarg -- cgit v1.2.3 From 889a07f5563a0f970639a0958c0dcbc26e82919f Mon Sep 17 00:00:00 2001 From: Tom Christie Date: Fri, 23 Jan 2015 15:32:21 +0000 Subject: Support assignment in ClassLookupDict --- rest_framework/utils/field_mapping.py | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rest_framework/utils/field_mapping.py') diff --git a/rest_framework/utils/field_mapping.py b/rest_framework/utils/field_mapping.py index cba40d31..c97ec5d0 100644 --- a/rest_framework/utils/field_mapping.py +++ b/rest_framework/utils/field_mapping.py @@ -38,6 +38,9 @@ class ClassLookupDict(object): return self.mapping[cls] raise KeyError('Class %s not found in lookup.', cls.__name__) + def __setitem__(self, key, value): + self.mapping[key] = value + def needs_label(model_field, field_name): """ -- cgit v1.2.3