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

use*_*731 5 python django django-rest-framework

我有两个相关的模型(事件+位置),其串行器如下所示:

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
Run Code Online (Sandbox Code Playgroud)

我在序列化器中将depth设置为1,这样我就可以从Locations模型而不是单个模型中获取信息id。但是,在执行此操作时,我无法发布具有位置信息的事件。我只能执行带有title属性的帖子。如果删除序列化程序中的depth选项,则可以同时显示标题和位置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);
        });
}
Run Code Online (Sandbox Code Playgroud)

因此,当序列化程序处于平稳状态时,我可以发布所有这些字段。位置字段是相关位置表中位置的ID。当它们嵌套时,我不能在测试数据中包括位置字段。

Kev*_*own 2

通过在序列化器上设置该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'])
Run Code Online (Sandbox Code Playgroud)

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

另外,您应该避免型号名称为复数。Events.locations即使Locations.events是该位置的事件列表,当 是单个位置时还是令人困惑。Event.location并且Location.events读得更清楚一点,Django 管理员将合理地显示它们,并且您的开发人员同事将能够轻松理解这些关系是如何设置的。