【问题标题】:Django Rest Framework: POST and PUT in a single nested requestDjango Rest Framework:在单个嵌套请求中进行 POST 和 PUT
【发布时间】:2015-10-23 08:35:14
【问题描述】:

我正在使用 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 中所述。

然后我们有“飞行员”对象的情况。这将始终包含一个 ID 和一些其他字段来修补具有该 ID 的对象。

“typeratingexaminer”字段只是另一个“Pilot”对象,但它不应该被修补,只是设置为外键。

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

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

很高兴听到您对此的看法,我有点迷茫。

【问题讨论】:

    标签: python json django django-rest-framework


    【解决方案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 并不是真正的好方法。

    【讨论】:

    • 感谢您的回答。不过我确实有一个主对象,所以我将在视图中创建逻辑并使用不同的模型序列化程序。
    【解决方案2】:

    我建议不要使用序列化程序创建方法并在视图中构建您的扩展逻辑,您可以在需要时充分利用更简单、愚蠢的序列化程序。您可以在序列化程序的 create 方法中进行更新,但突然之间它不再是序列化程序了,它更像是一个控制器,因此通过覆盖 create 或 post 方法,它会更好地放置在视图代码中;这种设计使您只有一个来自客户端的请求,您可以在视图代码中处理请求数据,并使用简单的序列化程序来实例化/更新对象,如果需要,还可以使用嵌入式数据验证。

    如果您有可以分享的模型和序列化程序,我们也许可以就这一点发表更多评论。

    【讨论】:

    • 这听起来是最好的方法。谢谢!
    猜你喜欢
    • 2023-01-08
    • 1970-01-01
    • 2018-12-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-03
    • 2018-05-19
    • 2016-05-27
    相关资源
    最近更新 更多