Handle image upload with multipart form and nested data

I have the standard Django user model and a profile model that has a oneToone with the user. So the payload for creating the whole thing at once would be:

# models.py
class Profile(models.Model):
  user = models.OneToOneField(User)
  profile_picture = models.ImageField()
  # Other extra profile related information

# serializers.py
class ProfileSerializer(serializers.ModelSerializer):
  user = UserSerializer()
  class Meta:
    model = Profile
    fields = "__all__"

{
  "user": { "first_name": "", "last_name": ""},
  "profile_picture": <file>
}

this of course is sent as a multipart form since it contains image upload. But then you cannot send nested data with multipart form, I guess? I have write extra code to make it work. What’s the standard? Should it be created in multi step requests? So create a user, then create profile and attach image?

I was reading the DRF docs, and I guess I could use MultiParser/FormParser parsers but here’s what Claude says about this:

No, adding FormParser/MultiPartParser explicitly wouldn't help —
and here's why:

The problem is the format, not the parser.

MultiPartParser and FormParser are already the default DRF parsers
for multipart requests. Adding them explicitly changes nothing. The
fundamental limitation is that multipart/form-data is a flat
key=value format — it has no concept of nesting. When the browser
serializes a form, it can only produce things like:

 email=teacher@x.com
 professional_title=Therapist

There's no standard way to represent { "user": { "email": "..." } }
in a flat form. The parser faithfully reads what the HTTP spec says
— a flat structure — and produces a QueryDict. No parser can
reconstruct nesting that wasn't there.

So _coerce_data IS necessary when you have both a file + nested
data. The contract is: frontend sends user as a JSON.stringify()'d
string, backend parses it. That's the only clean way.

The real simplification would be to split it into two requests:

 1. POST /teachers/ with application/json → creates user + profile 
(no file, JSON handles nesting natively, _coerce_data not needed)
 2. PATCH /teachers/{id}/ with multipart/form-data → uploads 
profile_picture only (no nesting needed)

That's arguably cleaner UX too — you'd create the teacher first,
then optionally upload a photo.

Is this correct and the standard?

Please let me know if you require further clarification. I understand my question isn’t too clear.

Yes, the LLM gave you good feedback. I would likely do the same. Separate the file upload to a different API endpoint from the rest of the data.

No, the LLM answer is not accurate.

This is not described in the DRF documentation but the DRF serializers detect html-like input and unflatten such input to recreate the nested serializers structure: see django-rest-framework/rest_framework/utils/html.py at main · encode/django-rest-framework · GitHub

So, your example can be handled with multipart/form-data content type using the following form fields:

  • user.first_name

  • user.last_name

  • profile_picture

However, this is neither documented, nor it is a standard, so it’s up to you to stick with this DRF specific grammar or not.

Oh, good find! I had not run across that before.