Django Rest Framework:POST和PUT在一个嵌套请求中

时间:2015-10-23 08:35:14

标签: python json django django-rest-framework

我正在使用Django Rest Framework来创建一个对象。 JSON也包含嵌套对象;一组对象,用于创建和链接到"主要对象"以及应该部分更新的对象。

JSON看起来像这样:

{
  "opcitem_set" : [
    {
      "comment" : "Test comment",
      "grade" : "1",
      "name" : "1a"
    },
    {
      "comment" : "Test comment",
      "grade" : "2",
      "name" : "1b"
    },
    {
      "description" : "Additional test item",
      "comment" : "Additional comment",
      "grade" : "1",
      "name" : "extra_1"
    }
  ],
  "is_right_seat_training" : false,
  "checked_as" : "FC",
  "date" : "2015-10-23",
  "check_reason" : "Check ride",
  "opc_program" : "2",
  "is_pc" : true,
  "questionnaire_test_passed" : "Passed",
  "pnf_time" : 2,
  "other_comments_complete_crew" : "Other comments",
  "other_comments_flying_pilot" : "Other comments",
  "is_cat_2_training" : false,
  "opc_passed" : "Passed",
  "pilot" : {
    "pc_valid_to" : "2015-10-23",
    "id" : 721,
    "email" : "jens.nilsson@nextjet.se",
    "total_time" : 3120,
    "medical_valid_to" : "2015-10-23"
  },
  "pf_time" : 2,
  "aircraft_type" : "S340",
  "typeratingexaminer" : 734
}

" opcitem_set"包含应该创建的OpcItem类型的对象,并且具有到主对象的ForeignKey。到目前为止,我可以通过覆盖ModelSerializer上的create()方法来实现这一点,如http://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations中所述。

然后我们得到" pilot"宾语。这将始终包含一个ID和一些其他字段来PATCH具有该ID的对象。

" typeratingexaminer"领域只是另一个" Pilot"对象,但它不应该被PATCH,只需设置为外键。

我的问题是:我可以修补(部分更新)"飞行员"以及在create()方法中,还是会破坏某种设计模式?既然它真的是PATCH而不是POST,我应该在原始请求完成后在单独的请求中执行吗?在这种情况下,我可以拥有一个跨越两个请求的事务,这样如果第二个请求失败,第一个请求将被回滚吗?

希望能够仅从客户端发送一个请求,而不是在两个请求中将其拆分。也许您可以在ViewSet中分离JSON并将其发送到不同的序列化器?

很高兴听到您的想法,我有点迷失。

2 个答案:

答案 0 :(得分:1)

如果你没有创建一个主对象但只创建嵌套对象,你应该在序列化器中覆盖.update()方法并做一些这样的思考:

def update(self, instance, validated_data):

    if 'opcitem_set' in validated_data:
        opcitem_set_data = validated_data.pop('opcitem_set')

    if 'pilot' in validated_data:
        pilot_data = validated_data.pop('pilot')

    ...

    for opcitem_set in opcitem_set_data:
        Opcitem.objects.create(main_object=instance,
                               **opcitem_set)

    current_pilot = self.instance.pilot
    current_pilot.pc_valid_to = pilot_data.get('name', current_pilot.pc_valid_to)
    ...
    current_pilot.save()

    """
    Update instance as well if you need
    """

    return instance

如果您还需要创建主对象,则需要覆盖.create()方法。但是,PATCHing pilot将不是一个很好的方法。

答案 1 :(得分:-1)

我建议远离序列化器创建方法并在视图中构建您的广泛逻辑,您可以在需要时充分利用更简单,愚蠢的序列化器。您可以在序列化程序的create方法中进行更新,但突然间它不再是序列化程序,它更像是一个控制器,因此通过覆盖创建或更好地放置在视图代码中后方法;这种设计使您只能从客户端获得一个请求,您可以在视图代码中按摩请求数据,并使用简单的序列化程序来实例化/更新对象,并在需要时使用嵌入式数据验证。

如果您有可以分享的模型和序列化程序,我们可能会对此进行更多评论。