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

咨询:Django中Post请求向多模型序列化器传参的优化方案

问题

我是Django新手,需要将接收到的JSON对象拆分后存储到3个关联的Django模型中。现有代码可正常运行,但视图层代码冗余,想了解更简洁的实现方式。

接收的JSON数据

[{
    "contact_entry": {
        "employee_name" : "Tom Hanks",
        "employee_type" : "Full-time permanent"
    },
    "address" : {
        "line1": "1435 Manhattan Ave",
        "line2": "Apt 123",
        "city": "New York",
        "state": "New York",
        "country":"US"
    },
    "phone_number" : {
        "work_number": "9901948626",
        "home_number": "9908847555"
    }
}]

对应的Django模型

class ContactEntry(models.Model):
    employee_name = models.CharField(max_length=128)
    employee_type = models.CharField(max_length=128)
    
class Address(models.Model):
    contact_entry = models.ForeignKey(ContactEntry, on_delete=models.CASCADE)
    line1 = models.CharField(max_length=128)
    line2 = models.CharField(max_length=128)
    city = models.CharField(max_length=128)
    state = models.CharField(max_length=128)
    country = models.CharField(max_length=128)

class PhoneNumber(models.Model):
    contact_entry = models.ForeignKey(ContactEntry, on_delete=models.CASCADE)
    work_number = models.IntegerField(max_length=10)
    home_number = models.IntegerField(max_length=10)

原序列化器代码

class ContactEntrySerializer(serializers.ModelSerializer):
    class Meta:
        model = ContactEntry
        fields = '__all__'

class AddressSerializer(serializers.ModelSerializer):
    class Meta:
        model = Address
        fields = '__all__'

class PhoneNumberSerializer(serializers.ModelSerializer):
    class Meta:
        model = PhoneNumber
        fields = '__all__'

class CombinedSerializer(serializers.Serializer):
    contact_entry = ContactEntrySerializer()
    phone_number = PhoneNumberSerializer()
    address = AddressSerializer()

原视图Post方法

class CombinedContactView(APIView):

    def post(self, request, *args, **kwargs):

        # Validate JSON data with the serializer
        serializer = CombinedSerializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
        validated_data = serializer.validated_data.pop()

        contact_entry_data = validated_data['contact_entry']
        address_data = validated_data['address']
        phone_number_data = validated_data['phone_number']

        # Create model for contact book entry
        contact_entry_model = ContactEntry(**contact_entry_data)
        contact_entry_model.save()

        # Create model for address
        address_data['contact_entry'] = contact_entry_model
        address_model = Address(**address_data)
        address_model.save()

        # Create model for phone_number
        phone_number_data['contact_entry'] = contact_entry_model
        phone_number_model = PhoneNumber(**phone_number_data)
        phone_number_model.save()

        return HttpResponse(status=201)
优化方案

你可以通过将模型创建逻辑移到序列化器内部并利用数据库事务来简化视图代码,同时保证数据一致性。以下是具体实现:

1. 扩展CombinedSerializer,实现create方法

把原本在视图里的模型创建逻辑迁移到序列化器中,并加入原子事务确保数据完整性:

from django.db import transaction

class CombinedSerializer(serializers.Serializer):
    contact_entry = ContactEntrySerializer()
    phone_number = PhoneNumberSerializer()
    address = AddressSerializer()

    def create(self, validated_data):
        # 原子事务:三个模型要么全部创建成功,要么全部回滚
        with transaction.atomic():
            # 创建主模型ContactEntry
            contact_entry = ContactEntry.objects.create(**validated_data['contact_entry'])
            
            # 关联创建Address
            Address.objects.create(contact_entry=contact_entry, **validated_data['address'])
            
            # 关联创建PhoneNumber
            PhoneNumber.objects.create(contact_entry=contact_entry, **validated_data['phone_number'])
            
            return validated_data

2. 简化视图代码

视图只需要负责数据验证和调用序列化器的save方法,无需手动处理每个模型的创建:

class CombinedContactView(APIView):
    def post(self, request, *args, **kwargs):
        serializer = CombinedSerializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        
        return HttpResponse(status=201)

额外说明

  • transaction.atomic()避免了部分数据写入的问题:如果Address或PhoneNumber创建失败,已经创建的ContactEntry会自动回滚。
  • 使用objects.create()比手动实例化模型再调用save()更简洁高效。
  • 业务逻辑从视图迁移到序列化器,符合DRF的职责分离设计,让视图更专注于处理HTTP请求响应。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 04:27:29