Django REST Framework: creating hierarchical objects using URL arguments

django, django-rest-framework, python, rest

Solution

Make the parent object serializer field read_only. It's not optional but it's not coming from the request data either. Instead you pull the pk/slug from the URL in `pre_save()`...

# Assuming list and detail URLs like:
#   /v1/objects/<parent_pk>/subobjects/
#   /v1/objects/<parent_pk>/subobjects/<pk>/
def pre_save(self, obj):
    parent = models.MainObject.objects.get(pk=self.kwargs['parent_pk'])
    obj.parent = parent

Problem

I have a django-rest-framework REST API with hierarchical resources. I want to be able to create subobjects by POSTing to `/v1/objects/<pk>/subobjects/` and have it automatically set the foreign key on the new subobject to the `pk` kwarg from the URL without having to put it in the payload. Currently, the serializer is causing a 400 error, because it expects the `object` foreign key to be in the payload, but it shouldn't be considered optional either. The URL of the subobjects is `/v1/subobjects/<pk>/` (since the key of the parent isn't necessary to identify it), so it is still required if I want to `PUT` an existing resource. Should I just make it so that you POST to `/v1/subobjects/` with the parent in the payload to add subobjects, or is there a clean way to pass the `pk` kwarg from the URL to the serializer? I'm using `HyperlinkedModelSerializer` and `ModelViewSet` as my respective base classes. Is there some recommended way of doing this? So far the only idea I had was to completely re-implement the ViewSets and make a custom Serializer class whose get_default_fields() comes from a dictionary that is passed in from the ViewSet, populated by its kwargs. This seems quite involved for something that I would have thought is completely run-of-the-mill, so I can't help but think I'm missing something. Every REST API I've ever seen that has writable endpoints has this kind of URL-based argument inference, so the fact that django-rest-framework doesn't seem to be able to do it at all seems strange.

Original source