当前位置:   article > 正文

【Django】ManyToManyField多对多字段的处理_manytomanyfield包含contain

manytomanyfield包含contain
1.ManyToManyField

我们在使用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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

ManyToManyField字段的特点是多对多,它会自动创建一个第三方表来记录双方关系,例如上面这个模型类在迁移建表的时候就会自动生成一张名为tb_article_collected_users的表,该表的字段只有id、article_id、user_id这三个字段
因为中间表的存在,我们在反序列化入库的时候就需要特别处理

2.处理方式
 模型类对象.中间表字段名.all()
 模型类对象.中间表字段名.add()
 模型类对象.中间表字段名.remove()
 模型类对象.中间表字段名.clear()
  • 1
  • 2
  • 3
  • 4
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': '收藏成功'})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
3.手动管理第三方表

如果不使用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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号