【问题标题】:Django Rest Framework - Nested fields: Do not create but get one from existing recordsDjango Rest Framework - 嵌套字段:不创建但从现有记录中获取
【发布时间】:2026-01-30 06:10:01
【问题描述】:

假设我有一个 Appointment 模型。一个约会有一个医生和一个病人。 创建约会时,用户选择医生和患者。这意味着只创建实际的约会。不是医生和病人。

从数据库中检索约会时,我希望表示形式如下所示:

{
  id: 1,
  doctor: {
    id: 8,
    name: 'Dr James Brown',
    phone: '107-102-304',
  },
  patient: {
    id: 4,
    name: 'Mr Elvis',
    phone: '123-456'
  }
}

所以我的序列化器看起来像:

class AppointmentSerializer(serializers.ModelSerializer):

  id            = serializers.IntegerField(read_only=True)
  doctor        = ContactSerializer()
  patient       = ContactSerializer()

  class Meta:
    model  = Appointment
    fields = (
      'id',
      'doctor',
      'patient',
    )

我希望能够使用相同的序列化程序创建约会。这意味着我将 POST 到服务器的 JSON 看起来像这样(它与上面基本相同,没有 id 字段,因为它是一个新记录):

{
  doctor: {
    id: 9,
    name: 'Dr Otis Redding',
    phone: '107-102-304'
  },
  patient: {
    id: 4,
    name: 'Mr Ray Charles',
    phone: '123-456'
  }
}

我将选项 read_only=False 添加到我的序列化程序(这应该使字段可写):

  doctor        = ContactSerializer(read_only=False)
  patient       = ContactSerializer(read_only=False)

但这会引发错误:

无法分配“OrderedDict([(u'id', 14), (u'name', u'Josephine'), (u'phone', u'0123-456')])": "Appointment.doctor" 必须是 "Contact" 实例。

我希望能够告诉 Django-Rest-Framework:“不要创建医生和患者,而是通过 id 选择它们”。我知道在创建约会时没有必要发送整个陈述。只有实际的 id 是必需的。但同样,我这样做是因为我想使用相同的序列化程序并保持代码更简洁。

这有意义吗?这是 DRF 要走的路吗?

Ps:我注意到它在关系为 many=True 时有效。但是在我的情况下,预约只有一名医生和一名患者。

提前致谢。

【问题讨论】:

    标签: django nested django-rest-framework


    【解决方案1】:

    这就是我最终要做的,以防它对某人有用:

    class ContactField(serializers.Field):
    
      def to_internal_value(self, data)
        return Contact.objects.get(pk=data.get('id'))
    
      def to_representation(self, obj):
        return ContactSerializer(obj).data
    

    class AppointmentSerializer(serializers.ModelSerializer):
    
      id            = serializers.IntegerField(read_only=True)
      doctor        = ContactField()
      patient       = ContactField()
    
      class Meta:
        model  = Appointment
        fields = (
          'id',
          'doctor',
          'patient',
        )
    

    【讨论】: