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
相关产品推荐
相关产品推荐

