发布一对多的关系

goz*_*lli 9 django one-to-many django-rest-framework

我正试图通过Django REST框架向我的Django模型公开API.

我有一个对象Observation.观察可以包含已经观察到的多个事物.所以我这样代表它:

class Observation(models.Model):

    photo_file = models.ImageField( upload_to=img_dir,   blank=True, null=True )
    titestamp = models.DateTimeField(blank=True, null=True)
    latitude = models.FloatField()
    longitude = models.FloatField()


class ObservedThing(models.Model):
    thing = models.ForeignKey(Thing) # the thing being observed
    observation = models.ForeignKey(Observation, related_name='observed_thing')
    value = models.FloatField()
Run Code Online (Sandbox Code Playgroud)

据我所知,这是一对多的关系.

我现在有一个API视图:

class ObsvList(generics.ListCreateAPIView):
    """
    API endpoint that represents a list of observations.
    """
    model = Observation
    serializer_class = ObsvSerializer
Run Code Online (Sandbox Code Playgroud)

和相应的序列化器:

class ObsvSerializer(serializers.ModelSerializer):

    observed_thing = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Observation
Run Code Online (Sandbox Code Playgroud)

我需要做些什么才能通过检测到的几件东西发布观察?我想不明白.非常感谢.

Rob*_*gar 8

(或多或少从另一个类似但不太清楚的问题复制)

要在单个POST中创建多个相关对象,需要可写的嵌套序列化程序,这些序列化程序尚不可用.

完全支持是一项正在进行工作,但与此同时,一个(hacky)解决方案是create在每种情况下覆盖视图中的方法:

class FooListCreateView(ListCreateAPIView):
    model = Foo
    serializer_class = FooSerializer

    def create(self, request, *args, **kwargs):
        data=request.DATA

        f = Foo.objects.create()

        # ... create nested objects from request data ...  

        # ...
        return Response(serializer.data, 
                        status=status.HTTP_201_CREATED,
                        headers=headers)
Run Code Online (Sandbox Code Playgroud)

可能不理想,但它适用于我,直到正确的方式出现.

另一个选项是Observation使用单独的POST单独创建相关对象,并使用PrimaryKeyRelatedField或HyperlinkedRelatedField在最终ObservedThingPOST中创建关联.


gig*_*DIE 5

我知道这个帖子已经有了答案,但我开始努力解决这个问题,因为这篇文章是我的灵感之一,所以我想分享我的最终解决方案。它可能对某人有用。我有模型,所以父类:

#parent model class
class Parent(models.Model):

    id = models.AutoField(primary_key=True)
    field = models.CharField(max_length=45)

    class Meta:
        managed = False
        db_table = 'parent'
Run Code Online (Sandbox Code Playgroud)

然后,子类:

#child model class
class Child(models.Model):

    id = models.AutoField(primary_key=True)
    field = models.CharField(max_length=45)
    parent = models.ForeignKey(Parent, related_name='children')

    class Meta:
        managed = False
        db_table = 'child'
Run Code Online (Sandbox Code Playgroud)

我必须定义序列化程序,因为我不想创建路由器可访问的 url 来直接管理 Children 对象,但我想通过父 ModelViewSet 的 ModelViewSet 创建它们,这就是我需要的:

class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        model = Child
        read_only_fields = ('id',)

class ParentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Banner
        read_only_fields = ('id',)

class ParentSerializerNested(ParentSerializer):
    children = ChildSerializer(many=True)
Run Code Online (Sandbox Code Playgroud)

然后我准备创建 ModelViewSet,覆盖/扩展创建/更新混合,并使其通用以便在其他情况下重用它:

class ParentChildViewSet(viewsets.ModelViewSet):

    def create(self, request, *args, **kwargs):
        serializer = self.serializer_parent(data=request.DATA,
                                            files=request.FILES)

        try:
            if serializer.is_valid():
                with transaction.commit_on_success():
                    self.pre_save(serializer.object)
                    parent = serializer.save(force_insert=True)
                    self.post_save(parent, created=True)

                    # need to insert children records
                    for child in request.DATA[self.child_field]:
                        child[self.parent_field] = parent.id
                        child_record = self.serializer_child(data=child)
                        if child_record.is_valid():
                            child_record.save(force_insert=True)
                        else:
                            raise ValidationError('Child validation failed')

                    headers = self.get_success_headers(serializer.data)

                    serializer.data[self.child_field] = self.serializer_child(
                        self.model_child.objects.filter(
                            **{self.parent_field: parent.id}).all(),
                            many=True).data
                    return Response(serializer.data,
                                    status=status.HTTP_201_CREATED,
                                    headers=headers)
        except ValidationError:
            pass
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Run Code Online (Sandbox Code Playgroud)

所以我可以在我的应用程序中的每个嵌套关系案例中重复使用它,如下所示:

class ParentViewSet(ParentChildViewSet):
    child_field = 'children'
    parent_field = 'parent'
    model = Parent
    model_child = Child
    serializer_class = ParentSerializerNested
    serializer_parent = ParentSerializer
    serializer_child = ChildSerializer
Run Code Online (Sandbox Code Playgroud)

最后,路由:

router = routers.DefaultRouter()
router.register(r'parents', ParentViewSet)
Run Code Online (Sandbox Code Playgroud)

它就像一个魅力!


归档时间:

查看次数:

4368 次

最近记录:

11 年,7 月 前