如何使用相关模型发布到 Django REST 框架 API

Posted

技术标签:

【中文标题】如何使用相关模型发布到 Django REST 框架 API【英文标题】:How to post to a Django REST Framework API with Related Models 【发布时间】:2015-02-06 13:13:06 【问题描述】:

我有两个相关模型(事件 + 位置),序列化器如下所示:

class Locations
    title = models.CharField(max_length=250)
    address = model.CharField(max_length=250)

class Events
   title = models.CharField(max_length=250)
   locations = models.ForeignKey(Locations, related_name='events'

class EventsSerializer(serializers.ModelSerializer):
    class Meta:
        model = Events
        depth = 1

我在序列化程序中将深度设置为 1,因此我可以从 Locations 模型而不是单个 id 获取信息。但是,这样做时,我无法发布带有位置信息的事件。我只能执行带有标题属性的帖子。如果我删除序列化程序中的深度选项,我可以使用标题和位置 ID 执行帖子。

我尝试创建第二个序列化程序 (EventsSerialzerB) 没有深度场,目的是使用第一个作为只读响应,但是当我创建第二个序列化程序、视图集并将其添加到路由器时,它将自动覆盖原始视图集。

我是否可以创建一个输出相关模型字段的序列化程序,并允许您直接发布到单个模型?

// 编辑 - 这是我要发布的内容

$scope.doClick = function (event) 

    var test_data  = 
        title: 'Event Test',
        content: 'Some test content here',
        location: 2,
        date: '2014-12-16T11:00:00Z'
    

    // $resource.save() doesn't work?
    $http.post('/api/events/', test_data).
        success(function(data, status, headers, config) 
            console.log('sucess', status);
        ).
        error(function(data, status, headers, config) 
            console.log('error', status);
        );

所以当序列化器是扁平的时,我可以发布所有这些字段。 location 字段是相关 Locations 表中位置的 ID。当它们嵌套时,我无法在测试数据中包含位置字段。

【问题讨论】:

什么版本的 Django REST 框架? 我使用的是 3.0 版 当然,我更新了上面的问题 我能够通过使用 2 个不同的序列化程序来解决这个问题,一个代表获取请求的嵌套视图,另一个代表发布请求的平面视图,如下所示:***.com/questions/22616973/… 【参考方案1】:

通过在序列化程序上设置depth 选项,您可以告诉它使任何关系嵌套而不是平面关系。在大多数情况下,嵌套的序列化器默认应该被认为是只读的,因为它们在 Django REST Framework 2.4 中有错误,并且在 3.0 中有更好的方法来处理它们。

听起来您在阅读时需要嵌套表示,但在写作时需要平面表示。虽然不建议这样做,因为这意味着 GET 请求与 PUT 请求不匹配,但可以通过让每个人都满意的方式来执行此操作。

在 Django REST Framework 3.0 中,你可以尝试以下方法来获得你想要的:

class LocationsSerializer(serializers.ModelSerializer):

    class Meta:
        model = Locations
        fields = ('title', 'address', )

class EventsSerializer(serializers.ModelSerializer):
    locations = LocationsSerializer(read_only=True)

    class Meta:
        model = Events
        fields = ('locations', )

class EventViewSet(viewsets.ModelViewSet):
    queryet = Event.objects.all()
    serializer_class = EventsSerializer

    def perform_create(self, serializer):
        serializer.save(locations=self.request.data['locations'])

    def perform_update(self, serializer):
        serializer.save(locations=self.request.data['locations'])

创建了一个新的LocationsSerializer,它将处理Locations 对象的只读嵌套表示。通过覆盖perform_createperform_update,我们可以传入与请求正文一起传入的位置ID,因此仍然可以更新位置。

此外,您应该避免型号名称是复数形式。当Events.locations 是单个位置时会令人困惑,即使Locations.events 是该位置的事件列表。 Event.locationLocation.events 读的更清楚一点,Django admin 会合理的显示出来,你的开发者也能很容易地理解关系是如何设置的。

【讨论】:

这个解决方案仍然不允许我通过提供位置的 id 来发布新的事件项。我只能输入活动的信息。传统上,在处理像这样的相关模型时,我是否应该将两个序列化器分开并保持平坦,然后在前端与 JS 执行连接?或者我应该有一组用于只读嵌套数据的序列化程序,然后是另一组用于发布数据的平面序列化程序?

以上是关于如何使用相关模型发布到 Django REST 框架 API的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest Framework - 使用 ModelSerializer 和 ModelViewSet 更新相关模型

如何使 Vue.js 将散列密码发布到 Django REST API AbstractBaseUser 自定义模型?

Django REST 框架:使用相关字段创建/更新对象

如何在 django rest 框架中获取与外键相关的数据?

如何在 django rest 框架中的嵌套序列化器相关对象上使用 prefetch_related?

如何计算Django模型中某些字段的平均值并将其发送到rest API?