赞
踩
我们在使用DRF完成序列化的时候可能会遇到ManyToMany字段,这是多对多的字段。比如说下面的这个模型类
class Article(models.Model):
...
collected_users = models.ManyToManyField(User, symmetrical=False, related_name='collected_articles') # 被哪些用户收藏
class Meta:
db_table = "tb_article"
verbose_name = "文章"
verbose_name_plural = verbose_name
ManyToManyField字段的特点是多对多,它会自动创建一个第三方表来记录双方关系,例如上面这个模型类在迁移建表的时候就会自动生成一张名为tb_article_collected_users的表,该表的字段只有id、article_id、user_id这三个字段
因为中间表的存在,我们在反序列化入库的时候就需要特别处理
模型类对象.中间表字段名.all()
模型类对象.中间表字段名.add()
模型类对象.中间表字段名.remove()
模型类对象.中间表字段名.clear()
class ArticleViewSet(ModelViewSet): queryset = Article.objects.all() serializer_class = ArticleSerializer def get_article_by_collect(self, request, pk): user = request.user if not user.is_authenticated: return Response({"message":"请先登录"}) article = self.get_object() if user in article .collected_users.all(): article .collected_users.remove(user) # 删除数据 article .save() return Response({'success': True, 'message': '取消收藏'}) else: article .collected_users.add(user) # 增加数据 article .save() return Response({'success': True, 'message': '收藏成功'})
如果不使用ManyToManyField字段,可以手动再写一个模型类创建第三方表,不过处理的时候就稍微有点不一样
sku_view.py
class SKUGoodsView(ModelViewSet):
queryset = SKU.objects.all().order_by('pk')
serializer_class = SKUModelSerializer
pagination_class = MyPage
def get_queryset(self):
keyword = self.request.query_params.get('keyword')
if keyword:
return self.queryset.filter(name__contains=keyword)
return self.queryset.all()
sku_serializers.py
class SKUModelSerializer(serializers.ModelSerializer): spu = serializers.StringRelatedField() spu_id = serializers.IntegerField() category = serializers.StringRelatedField() category_id = serializers.IntegerField() specs = SKUSpecOptModelSerializer(many=True) class Meta: model = SKU fields = '__all__' # 重写create原因: # 默认的create无法帮助我们插入中间表数据来记录新增SKU商品的规格和选项信息 def create(self, validated_data): specs = validated_data.pop('specs') validated_data['default_image'] = 'group1/M00/00/02/CtM3BVrPB4GAWkTlAAGuN6wB9fU4220429' # 开启事务 with transaction.atomic(): save_id = transaction.savepoint() try: sku = SKU.objects.create(**validated_data) for temp in specs: temp['sku_id'] = sku.id SKUSpecification.objects.create(**temp) except Exception as e: transaction.savepoint_rollback(save_id) raise serializers.ValidationError('数据库新建失败') transaction.savepoint_commit(save_id) generate_static_sku_detail_html.delay(sku.id) return sku # 默认的update方法,无法完成中间表数据的更新 def update(self, instance, validated_data): specs = validated_data.pop('specs') # 更新主表数据 sku = super().update(instance,validated_data) # 删除原有中间表的数据 SKUSpecification.objects.filter( sku_id = sku.id ).delete() # 插入新的规格和选项到中间表 for temp in specs: temp['sku_id'] = sku.id SKUSpecification.objects.create(**temp) return sku
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。