First pass at HTMLFormRenderer

This commit is contained in:
Tom Christie 2013-08-23 14:38:31 +01:00
parent f54fc3a76b
commit 0966a2680b
2 changed files with 58 additions and 49 deletions

View File

@ -316,6 +316,59 @@ class StaticHTMLRenderer(TemplateHTMLRenderer):
return data
class HTMLFormRenderer(BaseRenderer):
template = 'rest_framework/form.html'
def serializer_to_form_fields(self, serializer):
fields = {}
for k, v in serializer.get_fields().items():
if getattr(v, 'read_only', True):
continue
kwargs = {}
kwargs['required'] = v.required
#if getattr(v, 'queryset', None):
# kwargs['queryset'] = v.queryset
if getattr(v, 'choices', None) is not None:
kwargs['choices'] = v.choices
if getattr(v, 'regex', None) is not None:
kwargs['regex'] = v.regex
if getattr(v, 'widget', None):
widget = copy.deepcopy(v.widget)
kwargs['widget'] = widget
if getattr(v, 'default', None) is not None:
kwargs['initial'] = v.default
if getattr(v, 'label', None) is not None:
kwargs['label'] = v.label
if getattr(v, 'help_text', None) is not None:
kwargs['help_text'] = v.help_text
fields[k] = v.form_field_class(**kwargs)
return fields
def render(self, serializer, obj, request):
fields = self.serializer_to_form_fields(serializer)
# Creating an on the fly form see:
# http://stackoverflow.com/questions/3915024/dynamically-creating-classes-python
OnTheFlyForm = type(str("OnTheFlyForm"), (forms.Form,), fields)
data = (obj is not None) and serializer.data or None
form_instance = OnTheFlyForm(data)
template = loader.get_template(self.template)
context = RequestContext(request, {'form': form_instance})
return template.render(context)
class BrowsableAPIRenderer(BaseRenderer):
"""
HTML renderer used to self-document the API.
@ -371,41 +424,6 @@ class BrowsableAPIRenderer(BaseRenderer):
return False # Doesn't have permissions
return True
def serializer_to_form_fields(self, serializer):
fields = {}
for k, v in serializer.get_fields().items():
if getattr(v, 'read_only', True):
continue
kwargs = {}
kwargs['required'] = v.required
#if getattr(v, 'queryset', None):
# kwargs['queryset'] = v.queryset
if getattr(v, 'choices', None) is not None:
kwargs['choices'] = v.choices
if getattr(v, 'regex', None) is not None:
kwargs['regex'] = v.regex
if getattr(v, 'widget', None):
widget = copy.deepcopy(v.widget)
kwargs['widget'] = widget
if getattr(v, 'default', None) is not None:
kwargs['initial'] = v.default
if getattr(v, 'label', None) is not None:
kwargs['label'] = v.label
if getattr(v, 'help_text', None) is not None:
kwargs['help_text'] = v.help_text
fields[k] = v.form_field_class(**kwargs)
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
@ -447,14 +465,7 @@ class BrowsableAPIRenderer(BaseRenderer):
return
serializer = view.get_serializer(instance=obj)
fields = self.serializer_to_form_fields(serializer)
# Creating an on the fly form see:
# http://stackoverflow.com/questions/3915024/dynamically-creating-classes-python
OnTheFlyForm = type(str("OnTheFlyForm"), (forms.Form,), fields)
data = (obj is not None) and serializer.data or None
form_instance = OnTheFlyForm(data)
return form_instance
return HTMLFormRenderer().render(serializer, obj, request)
def get_raw_data_form(self, view, method, request, media_types):
"""

View File

@ -136,9 +136,9 @@
{% if post_form %}
<div class="tab-pane" id="object-form">
{% with form=post_form %}
<form action="{{ request.get_full_path }}" method="POST" {% if form.is_multipart %}enctype="multipart/form-data"{% endif %} class="form-horizontal">
<form action="{{ request.get_full_path }}" method="POST" enctype="multipart/form-data" class="form-horizontal">
<fieldset>
{% include "rest_framework/form.html" %}
{{ post_form }}
<div class="form-actions">
<button class="btn btn-primary" title="Make a POST request on the {{ name }} resource">POST</button>
</div>
@ -174,16 +174,14 @@
<div class="well tab-content">
{% if put_form %}
<div class="tab-pane" id="object-form">
{% with form=put_form %}
<form action="{{ request.get_full_path }}" method="POST" {% if form.is_multipart %}enctype="multipart/form-data"{% endif %} class="form-horizontal">
<form action="{{ request.get_full_path }}" method="POST" enctype="multipart/form-data" class="form-horizontal">
<fieldset>
{% include "rest_framework/form.html" %}
{{ put_form }}
<div class="form-actions">
<button class="btn btn-primary js-tooltip" name="{{ api_settings.FORM_METHOD_OVERRIDE }}" value="PUT" title="Make a PUT request on the {{ name }} resource">PUT</button>
</div>
</fieldset>
</form>
{% endwith %}
</div>
{% endif %}
<div {% if put_form %}class="tab-pane"{% endif %} id="generic-content-form">