You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django DRF创建父表记录后插入子表数据并返回关联结果

解决Django REST Framework中子表数据关联插入问题

问题背景

在使用Django REST Framework时,需要实现创建Card记录后,自动插入关联的ContactName子表数据,设置子表的card_id为新创建Card的ID,并在响应中返回包含关联记录的完整数据。


现有代码

models.py

class Card(models.Model):
    image = models.ImageField(upload_to='images', max_length=255, null=True, blank=True)
    filename = models.CharField(max_length=255, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.filename

class ContactName(models.Model):
    first_name = models.CharField(max_length=255, null=True, blank=True)
    last_name = models.CharField(max_length=255, null=True, blank=True)
    confidence = models.FloatField(default=0)
    card = models.ForeignKey(Card, on_delete=models.CASCADE, related_name='contact_name')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.first_name

serializers.py

class ContactNameSerializer(serializers.ModelSerializer):
    class Meta:
        model = ContactName
        fields = ['id', 'first_name', 'last_name', 'confidence', 'card', 'created_at', 'updated_at']


class CardSerializer(serializers.ModelSerializer):
    contact_name = ContactNameSerializer(many=True, read_only=True)
    class Meta:
        model = Card
        fields = ['id', 'image', 'filename', 'contact_name', 'created_at', 'updated_at']

当前views.py(未完成版)

class CardViewSet(viewsets.ModelViewSet):
    parser_classes = (MultiPartParser, FormParser)

    queryset = Card.objects.all()
    serializer_class = CardSerializer

    def create(self, request):
        cards_serializer = CardSerializer(data=request.data)
        if cards_serializer.is_valid():
            cards_serializer.save()

            # insert the record into the child table and set the reference (card_id) as an id
            json = [
                {
                    "first_name": "John",
                    "last_name": "Doe",
                    "confidence": 0.9
                },
                {
                    "first_name": "Doe",
                    "last_name": "John",
                    "confidence": 0.5
                }
            ]

            return Response(cards_serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(cards_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

期望响应格式

{
  "id": 10,
  "image": "/media/abc.jpg",
  "filename": "abc.jpg",
  "contact_name": [
    {
      "id": 1,
      "first_name": "John",
      "last_name": "Doe",
      "confidence": 0.9,
      "card_id": 10
    },
    {
      "id": 2,
      "first_name": "Doe",
      "last_name": "John",
      "confidence": 0.5,
      "card_id": 10
    }
  ]
}

解决方案

1. 调整序列化器(适配响应字段)

如果需要响应中显示card_id而非外键对象card,修改ContactNameSerializer:

class ContactNameSerializer(serializers.ModelSerializer):
    card_id = serializers.PrimaryKeyRelatedField(source='card', read_only=True)
    class Meta:
        model = ContactName
        fields = ['id', 'first_name', 'last_name', 'confidence', 'card_id', 'created_at', 'updated_at']

CardSerializer保持原有配置即可,确保关联字段contact_name能正确序列化子表数据。

2. 完善ViewSet的create方法

在保存Card实例后,批量创建关联的ContactName记录,并重新序列化Card以包含最新关联数据:

from rest_framework import status
from rest_framework.response import Response

class CardViewSet(viewsets.ModelViewSet):
    parser_classes = (MultiPartParser, FormParser)
    queryset = Card.objects.all()
    serializer_class = CardSerializer

    def create(self, request):
        cards_serializer = CardSerializer(data=request.data)
        if cards_serializer.is_valid():
            # 保存Card实例并获取对象
            card_instance = cards_serializer.save()
            
            # 准备ContactName数据,绑定当前Card的ID作为外键
            contact_data_list = [
                {
                    "first_name": "John",
                    "last_name": "Doe",
                    "confidence": 0.9,
                    "card": card_instance.id
                },
                {
                    "first_name": "Doe",
                    "last_name": "John",
                    "confidence": 0.5,
                    "card": card_instance.id
                }
            ]
            
            # 批量验证并保存ContactName记录
            contact_serializer = ContactNameSerializer(data=contact_data_list, many=True)
            if contact_serializer.is_valid():
                contact_serializer.save()
            
            # 重新序列化Card实例,确保包含最新创建的关联数据
            response_serializer = CardSerializer(card_instance)
            return Response(response_serializer.data, status=status.HTTP_201_CREATED)
        else:
            return Response(cards_serializer.errors, status=status.HTTP_400_BAD_REQUEST)

关键说明

  • 保存Card后通过card_instance.id绑定子表外键,确保关联关系正确
  • 使用many=True参数实现批量验证和保存子表数据
  • 重新序列化Card实例,避免原序列化数据未包含新增的关联记录
  • 如果ContactName数据来自前端请求,只需将contact_data_list替换为request.data.get('contact_name', [])即可

内容的提问来源于stack exchange,提问作者Ven Nilson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 15:24:57