如何在Django REST Framework视图中批量保存关联模型数据?
Django REST API 多关联模型批量创建方案
一、基础模型对应关系(基于需求补全)
先对齐模型结构,确保关联逻辑清晰:
from django.db import models class Category(models.Model): name = models.CharField(max_length=100) class Product(models.Model): name = models.CharField(max_length=200) desc = models.TextField(null=True, blank=True) categories = models.ManyToManyField(Category, through='ProductsCategory') class ProductsCategory(models.Model): product = models.ForeignKey(Product, on_delete=models.CASCADE) category = models.ForeignKey(Category, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) class Pictures(models.Model): product = models.ForeignKey(Product, on_delete=models.CASCADE) image = models.ImageField(upload_to='product_pics/') alt_text = models.CharField(max_length=100, null=True, blank=True)
二、序列化器编写(处理嵌套关联)
自定义序列化器,单独处理多对多中间表和外键图片的嵌套输入:
from rest_framework import serializers from django.db import transaction from .models import Product, ProductsCategory, Pictures, Category class CategorySerializer(serializers.ModelSerializer): class Meta: model = Category fields = ['id', 'name'] class ProductsCategorySerializer(serializers.ModelSerializer): category = serializers.PrimaryKeyRelatedField(queryset=Category.objects.all()) class Meta: model = ProductsCategory fields = ['category'] class PicturesSerializer(serializers.ModelSerializer): class Meta: model = Pictures fields = ['image', 'alt_text'] class ProductCreateSerializer(serializers.ModelSerializer): categories = ProductsCategorySerializer(many=True) pictures = PicturesSerializer(many=True) class Meta: model = Product fields = ['name', 'desc', 'categories', 'pictures'] def create(self, validated_data): # 剥离关联数据,单独处理 categories_data = validated_data.pop('categories') pictures_data = validated_data.pop('pictures') # 原子事务保证数据一致性 with transaction.atomic(): product = Product.objects.create(**validated_data) # 批量创建多对多关联 category_relations = [ ProductsCategory(product=product, category=item['category']) for item in categories_data ] ProductsCategory.objects.bulk_create(category_relations) # 批量创建附属图片 pictures = [ Pictures(product=product, **pic_data) for pic_data in pictures_data ] Pictures.objects.bulk_create(pictures) return product
三、视图层实现
用ModelViewSet快速实现CRUD,聚焦创建逻辑:
from rest_framework import viewsets from .models import Product from .serializers import ProductCreateSerializer class ProductViewSet(viewsets.ModelViewSet): queryset = Product.objects.all() serializer_class = ProductCreateSerializer
四、输入数据格式示例
POST请求分两种情况:
- 纯JSON(仅用于测试,图片需用文件上传):
{ "name": "新款无线耳机", "desc": "降噪功能,续航24小时", "categories": [ {"category": 1}, {"category": 3} ], "pictures": [ {"alt_text": "耳机正面"}, {"alt_text": "耳机充电仓"} ] }
- 文件上传(生产环境用):
请求头设为Content-Type: multipart/form-data,图片字段提交文件流,其他字段按表单或JSON提交。
五、核心优化点
- 原子事务:用
transaction.atomic()包裹所有操作,避免主产品创建成功但关联数据保存失败的不一致情况。 - 批量创建:用
bulk_create替代循环创建,大幅提升大数量关联数据的写入性能。 - 前置验证:在序列化器
validate方法中添加自定义规则,比如检查分类ID是否存在、图片格式是否合法,提前拦截无效数据:def validate(self, attrs): category_ids = [item['category'].id for item in attrs['categories']] if not Category.objects.filter(id__in=category_ids).count() == len(category_ids): raise serializers.ValidationError("部分分类ID不存在") return attrs - 异常处理:捕获创建过程中的异常,返回友好错误信息,避免服务器崩溃。
内容的提问来源于stack exchange,提问作者Navid Vali
相关产品推荐
相关产品推荐

