class AnnotationSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Annotation
class ImageSerializer(serializers.HyperlinkedModelSerializer):
annotations = AnnotationSerializer(many=True, required=False)
class Meta:
depth = 1
model = Image
exclude = ('owner‘,)
An annotation has an image foreign key attribute and so images have potentially multiple annotations. I’d like to create an image with nested annotations via a post request to an images endpoint including the list of annotations for this image. Posting my data json encoded to the images endpoint does work and creates an image with appropriate annotations.
But when I try to upload an actual image, I have to use a multipart/form-encoded post request instead of a json one to make fileupload possible. And now I’m having a hard time getting my nested list of image annotations included in this request. Maybe I could put a json encoded string in some form-field and manually parse it in the view, overwriting request.DATA, but this seems to be really ugly.
I wonder whether there’s a better way to achieve what I’m trying to do :).
The neatest way I've found to solve this problem is to write a custom parser which parses the incoming multipart request. I've been using formencode to do the actual parsing but you could use any nested formdata library. This takes surprisingly little code:
from rest_framework import parsers
from formencode.variabledecode import variable_decode
class MultipartFormencodeParser(parsers.MultiPartParser):
def parse(self, stream, media_type=None, parser_context=None):
result = super().parse(
stream,
media_type=media_type,
parser_context=parser_context
)
data = variable_decode(result.data)
return parsers.DataAndFiles(data, result.files)
And then in your ViewSet
class ImageViewSet(viewsets.ModelViewSet):
...
parsers = (MultipartFormencodeParser,)
...
Formencode represents lists as <key>-<index>
entries in the encoded form data and nested properties as <item>.<proprety>
. So in your example the client would need to encode annotations as something like "annotation-1.name"
in the request. Obviously you will still need to handle the update of nested data manually in the serializer as mentioned in the rest framework documentation here
What do you mean that having a hard time gettting the nested list of image annotations include in the request? When you send the multpart/form-data
post request, is the nested notation list data included in the request.data? (Please use request.data
instead of request.DATA
and request.FILES
). Please use some debug tools like pdb
to check your request.data
.
For supporting writable nested serializer, I think you should overrite the create()
function for POST
method, and you can find more details from here. Sorry for not giving the answer directly, I need more details about your models.
And if you want to post JSON
instead of multipart/form-data
, you can use base64
for representing the figure (But the size of the file will grow almost 33% larger).
you can use formencode.variabledecode.variable_decode()
example:
class ImageSerializer(serializers.HyperlinkedModelSerializer):
...
def to_internal_value(self, value):
return super(ImageSerializer, self).to_internal_value(variable_decode(value))