diff options
| author | Tom Christie | 2013-05-18 01:49:38 -0700 | 
|---|---|---|
| committer | Tom Christie | 2013-05-18 01:49:38 -0700 | 
| commit | b950b025bc66e3018d5f74e1494ff17f7742be75 (patch) | |
| tree | b286f3f8b14847213fb34d3cb115f4bacc470982 /rest_framework | |
| parent | 34776da9249a5d73f822b3562bc56a5674b10ac7 (diff) | |
| parent | aea040161ae29ec4b5335be5164aa8e5ada506e3 (diff) | |
| download | django-rest-framework-b950b025bc66e3018d5f74e1494ff17f7742be75.tar.bz2 | |
Merge pull request #850 from tomchristie/dynamic-forms
Forms in Broseable API support dynamic serializers based on request method
Diffstat (limited to 'rest_framework')
| -rw-r--r-- | rest_framework/renderers.py | 42 | ||||
| -rw-r--r-- | rest_framework/tests/generics.py | 34 | 
2 files changed, 66 insertions, 10 deletions
| diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py index 1917a080..8361cd40 100644 --- a/rest_framework/renderers.py +++ b/rest_framework/renderers.py @@ -336,7 +336,7 @@ class BrowsableAPIRenderer(BaseRenderer):              return  # Cannot use form overloading          try: -            view.check_permissions(clone_request(request, method)) +            view.check_permissions(request)          except exceptions.APIException:              return False  # Doesn't have permissions          return True @@ -372,6 +372,30 @@ class BrowsableAPIRenderer(BaseRenderer):          return fields +    def _get_form(self, view, method, request): +        # We need to impersonate a request with the correct method, +        # so that eg. any dynamic get_serializer_class methods return the +        # correct form for each method. +        restore = view.request +        request = clone_request(request, method) +        view.request = request +        try: +            return self.get_form(view, method, request) +        finally: +            view.request = restore + +    def _get_raw_data_form(self, view, method, request, media_types): +        # We need to impersonate a request with the correct method, +        # so that eg. any dynamic get_serializer_class methods return the +        # correct form for each method. +        restore = view.request +        request = clone_request(request, method) +        view.request = request +        try: +            return self.get_raw_data_form(view, method, request, media_types) +        finally: +            view.request = restore +      def get_form(self, view, method, request):          """          Get a form, possibly bound to either the input or output data. @@ -465,15 +489,15 @@ class BrowsableAPIRenderer(BaseRenderer):          renderer = self.get_default_renderer(view)          content = self.get_content(renderer, data, accepted_media_type, renderer_context) -        put_form = self.get_form(view, 'PUT', request) -        post_form = self.get_form(view, 'POST', request) -        patch_form = self.get_form(view, 'PATCH', request) -        delete_form = self.get_form(view, 'DELETE', request) -        options_form = self.get_form(view, 'OPTIONS', request) +        put_form = self._get_form(view, 'PUT', request) +        post_form = self._get_form(view, 'POST', request) +        patch_form = self._get_form(view, 'PATCH', request) +        delete_form = self._get_form(view, 'DELETE', request) +        options_form = self._get_form(view, 'OPTIONS', request) -        raw_data_put_form = self.get_raw_data_form(view, 'PUT', request, media_types) -        raw_data_post_form = self.get_raw_data_form(view, 'POST', request, media_types) -        raw_data_patch_form = self.get_raw_data_form(view, 'PATCH', request, media_types) +        raw_data_put_form = self._get_raw_data_form(view, 'PUT', request, media_types) +        raw_data_post_form = self._get_raw_data_form(view, 'POST', request, media_types) +        raw_data_patch_form = self._get_raw_data_form(view, 'PATCH', request, media_types)          raw_data_put_or_patch_form = raw_data_put_form or raw_data_patch_form          name = self.get_name(view) diff --git a/rest_framework/tests/generics.py b/rest_framework/tests/generics.py index 2799d143..15d87e86 100644 --- a/rest_framework/tests/generics.py +++ b/rest_framework/tests/generics.py @@ -2,7 +2,7 @@ from __future__ import unicode_literals  from django.db import models  from django.shortcuts import get_object_or_404  from django.test import TestCase -from rest_framework import generics, serializers, status +from rest_framework import generics, renderers, serializers, status  from rest_framework.tests.utils import RequestFactory  from rest_framework.tests.models import BasicModel, Comment, SlugBasedModel  from rest_framework.compat import six @@ -476,3 +476,35 @@ class TestFilterBackendAppliedToViews(TestCase):          response = instance_view(request, pk=1).render()          self.assertEqual(response.status_code, status.HTTP_200_OK)          self.assertEqual(response.data, {'id': 1, 'text': 'foo'}) + + +class TwoFieldModel(models.Model): +    field_a = models.CharField(max_length=100) +    field_b = models.CharField(max_length=100) + + +class DynamicSerializerView(generics.ListCreateAPIView): +    model = TwoFieldModel +    renderer_classes = (renderers.BrowsableAPIRenderer, renderers.JSONRenderer) + +    def get_serializer_class(self): +        if self.request.method == 'POST': +            class DynamicSerializer(serializers.ModelSerializer): +                class Meta: +                    model = TwoFieldModel +                    fields = ('field_b',) +            return DynamicSerializer +        return super(DynamicSerializerView, self).get_serializer_class() + + +class TestFilterBackendAppliedToViews(TestCase): + +    def test_dynamic_serializer_form_in_browsable_api(self): +        """ +        GET requests to ListCreateAPIView should return filtered list. +        """ +        view = DynamicSerializerView.as_view() +        request = factory.get('/') +        response = view(request).render() +        self.assertContains(response, 'field_b') +        self.assertNotContains(response, 'field_a') | 
