From d70615efbd71219a02254b901cf930f27705da1e Mon Sep 17 00:00:00 2001 From: Chris Meyers Date: Fri, 19 Feb 2016 14:46:19 -0500 Subject: [PATCH] bring back meta choice options lost in upgrade * status and launch_type OPTIONS choices were lost in the django + drf upgrade. This brings them back. --- awx/api/metadata.py | 21 +++++++++++++++++++ awx/api/serializers.py | 15 +++++++++++++ .../functional/api/test_unified_jobs_view.py | 17 +++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 awx/main/tests/functional/api/test_unified_jobs_view.py diff --git a/awx/api/metadata.py b/awx/api/metadata.py index 713f9f83a2..a11df8d1ce 100644 --- a/awx/api/metadata.py +++ b/awx/api/metadata.py @@ -4,6 +4,7 @@ # Django from django.core.exceptions import PermissionDenied from django.http import Http404 +from django.utils.encoding import force_text # Django REST Framework from rest_framework import exceptions @@ -17,8 +18,28 @@ from awx.main.models import InventorySource class Metadata(metadata.SimpleMetadata): + # DRF 3.3 doesn't render choices for read-only fields + # + # We want to render choices for read-only fields + # + # Note: This works in conjuction with logic in serializers.py that sets + # field property editable=True before calling DRF build_standard_field() + # Note: Consider expanding this rendering for more than just choices fields + def _render_read_only_choices(self, field, field_info): + if field_info.get('read_only') and hasattr(field, 'choices'): + field_info['choices'] = [ + { + 'value': choice_value, + 'display_name': force_text(choice_name, strings_only=True) + } + for choice_value, choice_name in field.choices.items() + ] + return field_info + def get_field_info(self, field): field_info = super(Metadata, self).get_field_info(field) + if hasattr(field, 'choices') and field.choices: + field_info = self._render_read_only_choices(field, field_info) # Indicate if a field has a default value. # FIXME: Still isn't showing all default values? diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 491e76ddb7..e01828b276 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -331,7 +331,22 @@ class BaseSerializer(serializers.ModelSerializer): return obj.active def build_standard_field(self, field_name, model_field): + + # DRF 3.3 serializers.py::build_standard_field() -> utils/field_mapping.py::get_field_kwargs() short circuits + # when a Model's editable field is set to False. The short circuit skips choice rendering. + # + # This logic is to force rendering choice's on an uneditable field. + # Note: Consider expanding this rendering for more than just choices fields + # Note: This logic works in conjuction with + if hasattr(model_field, 'choices') and model_field.choices: + was_editable = model_field.editable + model_field.editable = True + field_class, field_kwargs = super(BaseSerializer, self).build_standard_field(field_name, model_field) + if hasattr(model_field, 'choices') and model_field.choices: + model_field.editable = was_editable + if was_editable is False: + field_kwargs['read_only'] = True # Update help text for common fields. opts = self.Meta.model._meta.concrete_model._meta diff --git a/awx/main/tests/functional/api/test_unified_jobs_view.py b/awx/main/tests/functional/api/test_unified_jobs_view.py new file mode 100644 index 0000000000..ab9487bc38 --- /dev/null +++ b/awx/main/tests/functional/api/test_unified_jobs_view.py @@ -0,0 +1,17 @@ +import pytest + +from awx.main.models import UnifiedJob +from django.core.urlresolvers import reverse + +@pytest.mark.django_db +def test_options_fields_choices(instance, options, user): + + url = reverse('api:unified_job_list') + response = options(url, None, user('admin', True)) + + assert 'launch_type' in response.data['actions']['GET'] + assert 'choice' == response.data['actions']['GET']['launch_type']['type'] + assert UnifiedJob.LAUNCH_TYPE_CHOICES == response.data['actions']['GET']['launch_type']['choices'] + assert 'choice' == response.data['actions']['GET']['status']['type'] + assert UnifiedJob.STATUS_CHOICES == response.data['actions']['GET']['status']['choices'] +