What I want to do:
Django Rest Framework comes with a renderer for returning a HTML form from a serializer[1]. After poring through the docs and then through the code, I still cannot figure out how to get it to render a blank form.
What I think the problem might be:
I can't figure out how to instantiate a blank serializer. In the docs for DRF they say the serializer has a very similar API to django's forms. When you want a blank form in a template, you instantiate one with MyForm() and pass it to the template context. However when I try that with a serializer, the .data attribute is just {'detail': 'Not Found.'}
Please help
I feel like I must be missing something blindingly obvious because rendering a blank form seems like a pretty major use case for an HTMLFormRenderer.
Some Source Code
class CustomViewSet(ModelViewSet):
lookup_field = 'id'
pagination_class = MyCustomPagination
serializer_class = MyModelSerializer
renderer_classes = (JSONRenderer, BrowsableAPIRenderer, HTMLFormRenderer)
def create(self, request, *args, **kwargs):
# return an html form for GET requests to /api/my_model/create/.form
I'm pretty sure I have the urlconf wired up right that the request ends up in the right place, because when I GET /api/my_model/<pk>/.form
I get a form in response, with the model attributes pre-entered. I just want a way to get a blank form...
I can't figure out how to instantiate a blank serializer.
DRF allows you to initialize a serializer with no data and no instance attached to it. So in your case, your view code would just look like
serializer = self.get_serializer()
I feel like I must be missing something blindingly obvious because rendering a blank form seems like a pretty major use case for an HTMLFormRenderer.
From that point, serializer
should contain all of the information required to render a form. If you want to stick with the default forms as they are rendered by Django REST framework, you can use the HTMLFormRenderer
that they provide.
serializer = self.get_serializer()
renderer = HTMLFormRenderer()
form_html = renderer.render(serializer.data)
It's important to note that the HTMLFormRenderer
is not subject to standard deprecation policies. So if you do actually use it, make sure to follow any release notes closely when upgrading to make sure that things don't unexpectedly break.
I managed to return an html snippet for a form using the following method on my viewset:
class CustomViewSet(ModelViewSet):
@list_route()
def form(self, request, *args, **kwargs):
serializer = self.get_serializer()
renderer = HTMLFormRenderer()
form_html = renderer.render(serializer.data, renderer_context={
'template': 'rest_framework/api_form.html',
'request': request
})
return HttpResponse(form_html)
I needed to use a vanilla django HttpResponse, rather than rest framework's Response object, to prevent the Response object trying to re-render the form_html with the viewset's default renderer. Also, the list_route decorator is needed to get rest_framework's DefaultRouter to add a my_model/form/
endpoint, it doesn't mean the view has to return a list.
A serializer must declare at least one field in order to work with it.
To create a absolutely blank serializer just add a custom SerializerMethodField that returns None or a hidden field that accepts null values:
class EmptySerialiser(serializers.Serializer):
empty = serializers.SerializerMethodField()
def get_empty(self):
return None
or
class EmptySerialiser(serializers.Serializer):
empty = serializers.HiddenField(default=None,allow_null=True)