5

I'm trying to find an elegant solution to this problem encountered using the Django REST framework. We have a parent model with a child object and a one to one relationship. Our requirements are that the child object is optional, can be null and can also be patched to null from a previously existing value. Additionally, if the parent object is deleted the child object should be as well.

This simple set-up that recreates the problem:

class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        model = Child


class ParentSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Parent

    parent_value = serializers.CharField(required=False, max_length=1024)
    child = ChildSerializer(read_only=False, required=False, many=False)


class Parent(models.Model):
    class Meta:
        app_label = "testparent"

    parent_value = models.CharField(max_length=1024, null=True, blank=True)


class Child(models.Model):
    class Meta:
        app_label = "testparent"

    child_value = models.CharField(max_length=1024, null=True, blank=True)
    parent = models.ForeignKey(Parent, null=True, blank=True, related_name="child")


class ParentViewSet(viewsets.ModelViewSet):
    permission_classes = (AllowAny,)

    queryset = Parent.objects.all()
    serializer_class = ParentSerializer

This works:

{
    "parent_value": "abc", 
    "child": { "child_value": "something" }
}

This gets an error:

{
    "parent_value": "abc", 
    "child": null
}

Note that the child object is optional and by default the REST framework populates the field with null.

I'm using Django v.1.5.4 and REST framework v.2.3.13

The error:

Traceback:
File "{site-packages}/django/core/handlers/base.py" in get_response
  115.                         response = callback(request, *callback_args, **callback_kwargs)
File "{site-packages}/rest_framework/viewsets.py" in view
  78.             return self.dispatch(request, *args, **kwargs)
File "{site-packages}/django/views/decorators/csrf.py" in wrapped_view
  77.         return view_func(*args, **kwargs)
File "{site-packages}/rest_framework/views.py" in dispatch
  400.             response = self.handle_exception(exc)
File "{site-packages}/rest_framework/views.py" in dispatch
  397.             response = handler(request, *args, **kwargs)
File "{site-packages}/rest_framework/mixins.py" in create
  54.             self.object = serializer.save(force_insert=True)
File "{site-packages}/rest_framework/serializers.py" in save
  596.             self.save_object(self.object, **kwargs)
File "{site-packages}/rest_framework/serializers.py" in save_object
  1023.                     setattr(obj, accessor_name, related)
File "{site-packages}/django/db/models/fields/related.py" in __set__
  474.         manager.add(*value)


Exception Value: add() argument after * must be a sequence, not NoneType

The workaround we're currently using is to have a OneToOne field for parent and then use a post_delete signal handler to delete the child object. This feels very hacky. We've in general have encountered a few issues with trying to manipulate nested objects and are wondering if we're going about it wrong or if maybe in this case we've encountered a bug in either django or the rest framework.

Thanks!

2
  • Have you tried using a PK related field instead of a child serializer? I believe, given your model, this would work. Commented Jul 17, 2014 at 9:56
  • We ended up having to create validation functions to protect against the null condition. Our conclusion was that the django rest framework's nested object functionality simply isn't mature yet and there are use cases that simply aren't handled in the code. Commented Aug 14, 2014 at 21:20

2 Answers 2

2

While this question was asked a year ago, Django Rest Framework has released a major update (3.1.1) since then which simplifies and enhances how the framework deals with nested objects.

Your requirements:

  1. One to One relationship - In the parent Serializer definition, you can specify the paramter many=False.

  2. Delete a Child Object when a Parent is deleted - In the Parent Serializer, implement the perform_destroy function. In this function, delete the Parent instance and Child instance.

Here is the DRF Serializer documentation

Sign up to request clarification or add additional context in comments.

Comments

1

Have you tried setting allow_null = True in the ChildSerializer?

1 Comment

Yes, you are right, this is working with allow_null = True. I have followed the same and verify it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.