Django Rest框架嵌套对象

5
我正在尝试为使用Django REST框架时遇到的问题寻找优雅的解决方案。我们有一个父模型和一个子对象,它们之间是一对一的关系。我们的要求是子对象是可选的,可以为空,并且还可以从先前存在的值被修补为null。另外,如果删除了父对象,则子对象也应该被删除。
以下是重新创建问题的简单设置:
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

这个有效:

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

这会出现错误:

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

请注意,子对象是可选的,默认情况下,REST框架将使用null填充该字段。
我正在使用Django v.1.5.4和REST框架v.2.3.13。
错误:
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

我们目前使用的解决方法是,为父对象创建一个 OneToOne 字段,然后使用 post_delete 信号处理程序删除子对象。这种方法感觉非常不专业。我们在试图操作嵌套对象时遇到了一些问题,因此想知道我们是否走错了路,或者说在这种情况下,我们是否遇到了 Django 或 Rest Framework 中的错误。

谢谢!


你尝试过使用主键相关字段而不是子序列化器吗?我相信,根据你的模型,这应该可以工作。 - AdelaN
我们最终不得不创建验证函数来防止空条件。我们的结论是,Django Rest Framework的嵌套对象功能还不够成熟,有些用例在代码中根本没有处理。 - JamesHutchison
2个回答

2
尽管这个问题是一年前提出的,但自那时以来,Django Rest Framework已经发布了一个重大更新(3.1.1),简化和增强了框架处理嵌套对象的方式。
您的要求:
1. 一对一关系 - 在父序列化器定义中,您可以指定参数many=False。 2. 当删除父对象时删除子对象 - 在父序列化器中,实现perform_destroy函数。在此函数中,删除父实例和子实例。 这里是DRF序列化器文档

1

你尝试过在ChildSerializer中设置allow_null = True吗?


是的,你说得对,这个选项设置为 allow_null = True 是有效的。我已经按照您的建议进行了验证。 - Shubham Singhal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接