mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-10 19:56:59 +03:00
Cleanup and dealing with empty form data.
This commit is contained in:
parent
b72a99fef2
commit
10d386ec6a
|
@ -244,6 +244,8 @@ class PrimaryKeyRelatedField(RelatedField):
|
|||
source = self.source or field_name
|
||||
queryset = obj
|
||||
for component in source.split('.'):
|
||||
if queryset is None:
|
||||
return []
|
||||
queryset = get_component(queryset, component)
|
||||
|
||||
# Forward relationship
|
||||
|
|
|
@ -319,52 +319,53 @@ class StaticHTMLRenderer(TemplateHTMLRenderer):
|
|||
class HTMLFormRenderer(BaseRenderer):
|
||||
template = 'rest_framework/form.html'
|
||||
|
||||
def serializer_to_form_fields(self, serializer):
|
||||
def data_to_form_fields(self, data):
|
||||
fields = {}
|
||||
for k, v in serializer.get_fields().items():
|
||||
if getattr(v, 'read_only', True):
|
||||
for key, val in data.fields.items():
|
||||
if getattr(val, 'read_only', True):
|
||||
continue
|
||||
|
||||
kwargs = {}
|
||||
kwargs['required'] = v.required
|
||||
kwargs['required'] = val.required
|
||||
|
||||
#if getattr(v, 'queryset', None):
|
||||
# kwargs['queryset'] = v.queryset
|
||||
|
||||
if getattr(v, 'choices', None) is not None:
|
||||
kwargs['choices'] = v.choices
|
||||
if getattr(val, 'choices', None) is not None:
|
||||
kwargs['choices'] = val.choices
|
||||
|
||||
if getattr(v, 'regex', None) is not None:
|
||||
kwargs['regex'] = v.regex
|
||||
if getattr(val, 'regex', None) is not None:
|
||||
kwargs['regex'] = val.regex
|
||||
|
||||
if getattr(v, 'widget', None):
|
||||
widget = copy.deepcopy(v.widget)
|
||||
if getattr(val, 'widget', None):
|
||||
widget = copy.deepcopy(val.widget)
|
||||
kwargs['widget'] = widget
|
||||
|
||||
if getattr(v, 'default', None) is not None:
|
||||
kwargs['initial'] = v.default
|
||||
if getattr(val, 'default', None) is not None:
|
||||
kwargs['initial'] = val.default
|
||||
|
||||
if getattr(v, 'label', None) is not None:
|
||||
kwargs['label'] = v.label
|
||||
if getattr(val, 'label', None) is not None:
|
||||
kwargs['label'] = val.label
|
||||
|
||||
if getattr(v, 'help_text', None) is not None:
|
||||
kwargs['help_text'] = v.help_text
|
||||
if getattr(val, 'help_text', None) is not None:
|
||||
kwargs['help_text'] = val.help_text
|
||||
|
||||
fields[k] = v.form_field_class(**kwargs)
|
||||
fields[key] = val.form_field_class(**kwargs)
|
||||
|
||||
return fields
|
||||
|
||||
def render(self, serializer, obj, request):
|
||||
fields = self.serializer_to_form_fields(serializer)
|
||||
def render(self, data, accepted_media_type=None, renderer_context=None):
|
||||
self.renderer_context = renderer_context or {}
|
||||
request = renderer_context['request']
|
||||
|
||||
# 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)
|
||||
fields = self.data_to_form_fields(data)
|
||||
DynamicForm = type(str('DynamicForm'), (forms.Form,), fields)
|
||||
data = None if data.empty else data
|
||||
|
||||
template = loader.get_template(self.template)
|
||||
context = RequestContext(request, {'form': form_instance})
|
||||
context = RequestContext(request, {'form': DynamicForm(data)})
|
||||
|
||||
return template.render(context)
|
||||
|
||||
|
@ -377,6 +378,7 @@ class BrowsableAPIRenderer(BaseRenderer):
|
|||
format = 'api'
|
||||
template = 'rest_framework/api.html'
|
||||
charset = 'utf-8'
|
||||
form_renderer_class = HTMLFormRenderer
|
||||
|
||||
def get_default_renderer(self, view):
|
||||
"""
|
||||
|
@ -424,7 +426,7 @@ class BrowsableAPIRenderer(BaseRenderer):
|
|||
return False # Doesn't have permissions
|
||||
return True
|
||||
|
||||
def _get_form(self, view, method, request):
|
||||
def _get_rendered_html_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.
|
||||
|
@ -432,27 +434,16 @@ class BrowsableAPIRenderer(BaseRenderer):
|
|||
request = clone_request(request, method)
|
||||
view.request = request
|
||||
try:
|
||||
return self.get_form(view, method, request)
|
||||
return self.get_rendered_html_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):
|
||||
def get_rendered_html_form(self, view, method, request):
|
||||
"""
|
||||
Get a form, possibly bound to either the input or output data.
|
||||
In the absence on of the Resource having an associated form then
|
||||
provide a form that can be used to submit arbitrary content.
|
||||
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.
|
||||
"""
|
||||
obj = getattr(view, 'object', None)
|
||||
if not self.show_form_for_method(view, method, request, obj):
|
||||
|
@ -465,7 +456,21 @@ class BrowsableAPIRenderer(BaseRenderer):
|
|||
return
|
||||
|
||||
serializer = view.get_serializer(instance=obj)
|
||||
return HTMLFormRenderer().render(serializer, obj, request)
|
||||
data = serializer.data
|
||||
form_renderer = self.form_renderer_class()
|
||||
return form_renderer.render(data, self.accepted_media_type, self.renderer_context)
|
||||
|
||||
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_raw_data_form(self, view, method, request, media_types):
|
||||
"""
|
||||
|
@ -520,8 +525,8 @@ class BrowsableAPIRenderer(BaseRenderer):
|
|||
"""
|
||||
Render the HTML for the browsable API representation.
|
||||
"""
|
||||
accepted_media_type = accepted_media_type or ''
|
||||
renderer_context = renderer_context or {}
|
||||
self.accepted_media_type = accepted_media_type or ''
|
||||
self.renderer_context = renderer_context or {}
|
||||
|
||||
view = renderer_context['view']
|
||||
request = renderer_context['request']
|
||||
|
@ -531,11 +536,11 @@ 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_rendered_html_form(view, 'PUT', request)
|
||||
post_form = self._get_rendered_html_form(view, 'POST', request)
|
||||
patch_form = self._get_rendered_html_form(view, 'PATCH', request)
|
||||
delete_form = self._get_rendered_html_form(view, 'DELETE', request)
|
||||
options_form = self._get_rendered_html_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)
|
||||
|
|
|
@ -300,7 +300,8 @@ class BaseSerializer(WritableField):
|
|||
Serialize objects -> primitives.
|
||||
"""
|
||||
ret = self._dict_class()
|
||||
ret.fields = {}
|
||||
ret.fields = self._dict_class()
|
||||
ret.empty = obj is None
|
||||
|
||||
for field_name, field in self.fields.items():
|
||||
field.initialize(parent=self, field_name=field_name)
|
||||
|
|
Loading…
Reference in New Issue
Block a user