def render(self, data, accepted_media_type=None, renderer_context=None): self.accepted_media_type = accepted_media_type or '' self.renderer_context = renderer_context or {} response = renderer_context['response'] request = renderer_context['request'] view = self.renderer_context['view'] if response.status_code == status.HTTP_400_BAD_REQUEST: # Errors still need to display the list or detail information. # The only way we can get at that is to simulate a GET request. self.error_form = self.get_rendered_html_form(data, view, request.method, request) self.error_title = {'POST': 'Create', 'PUT': 'Edit'}.get(request.method, 'Errors') with override_method(view, request, 'GET') as request: response = view.get(request, *view.args, **view.kwargs) data = response.data template = loader.get_template(self.template) context = self.get_context(data, accepted_media_type, renderer_context) ret = template_render(template, context, request=renderer_context['request']) # Creation and deletion should use redirects in the admin style. if (response.status_code == status.HTTP_201_CREATED) and ('Location' in response): response.status_code = status.HTTP_302_FOUND response['Location'] = request.build_absolute_uri() ret = '' if response.status_code == status.HTTP_204_NO_CONTENT: response.status_code = status.HTTP_302_FOUND try: # Attempt to get the parent breadcrumb URL. response['Location'] = self.get_breadcrumbs(request)[-2][1] except KeyError: # Otherwise reload current URL to get a 'Not Found' page. response['Location'] = request.full_path ret = '' return ret
def get_raw_data_form(self, data, view, method, request): """ Returns a form that allows for arbitrary content types to be tunneled via standard HTML forms. (Which are typically application/x-www-form-urlencoded) """ # See issue #2089 for refactoring this. serializer = getattr(data, 'serializer', None) if serializer and not getattr(serializer, 'many', False): instance = getattr(serializer, 'instance', None) if isinstance(instance, Page): instance = None else: instance = None with override_method(view, request, method) as request: # Check permissions if not self.show_form_for_method(view, method, request, instance): return # If possible, serialize the initial content for the generic form default_parser = view.parser_classes[0] renderer_class = getattr(default_parser, 'renderer_class', None) if (hasattr(view, 'get_serializer') and renderer_class): # View has a serializer defined and parser class has a # corresponding renderer that can be used to render the data. if method in ('PUT', 'PATCH'): serializer = view.get_serializer(instance=instance) else: serializer = view.get_serializer() # Render the raw data content renderer = renderer_class() accepted = self.accepted_media_type context = self.renderer_context.copy() context['indent'] = 4 content = renderer.render(serializer.data, accepted, context) else: content = None # Generate a generic form that includes a content type field, # and a content field. media_types = [parser.media_type for parser in view.parser_classes] choices = [(media_type, media_type) for media_type in media_types] initial = media_types[0] class GenericContentForm(forms.Form): _content_type = forms.ChoiceField( label='Media type', choices=choices, initial=initial, widget=forms.Select(attrs={'data-override': 'content-type'}) ) _content = forms.CharField( label='Content', widget=forms.Textarea(attrs={'data-override': 'content'}), initial=content ) return GenericContentForm()
def get_rendered_html_form(self, data, view, method, request): """ Return a string representing a rendered HTML form, possibly bound to either the input or output data. In the absence of the View having an associated form then return None. """ # See issue #2089 for refactoring this. serializer = getattr(data, 'serializer', None) if serializer and not getattr(serializer, 'many', False): instance = getattr(serializer, 'instance', None) if isinstance(instance, Page): instance = None else: instance = None # If this is valid serializer data, and the form is for the same # HTTP method as was used in the request then use the existing # serializer instance, rather than dynamically creating a new one. if request.method == method and serializer is not None: try: kwargs = {'data': request.data} except ParseError: kwargs = {} existing_serializer = serializer else: kwargs = {} existing_serializer = None with override_method(view, request, method) as request: if not self.show_form_for_method(view, method, request, instance): return if method in ('DELETE', 'OPTIONS'): return True # Don't actually need to return a form has_serializer = getattr(view, 'get_serializer', None) has_serializer_class = getattr(view, 'serializer_class', None) if ( (not has_serializer and not has_serializer_class) or not any(is_form_media_type(parser.media_type) for parser in view.parser_classes) ): return if existing_serializer is not None: serializer = existing_serializer else: if has_serializer: if method in ('PUT', 'PATCH'): serializer = view.get_serializer(instance=instance, **kwargs) else: serializer = view.get_serializer(**kwargs) else: # at this point we must have a serializer_class if method in ('PUT', 'PATCH'): serializer = self._get_serializer(view.serializer_class, view, request, instance=instance, **kwargs) else: serializer = self._get_serializer(view.serializer_class, view, request, **kwargs) if hasattr(serializer, 'initial_data'): serializer.is_valid() form_renderer = self.form_renderer_class() return form_renderer.render( serializer.data, self.accepted_media_type, {'style': {'template_pack': 'rest_framework/horizontal'}} )