DRF无请求体POST创建Subscription失败问题求助
问题排查与修复方案
核心问题分析
SubscriptionCreateSerializer无效:该序列化器的create方法仅写了pass,调用save()时无法生成数据库记录;同时设置fields='__all__',但请求无请求体,验证阶段会缺失必填字段,且代码未触发验证异常,后续逻辑强行执行导致报错。- 未实现订阅去重:未检查用户是否已订阅目标作者,可能导致重复创建订阅记录。
- 未返回指定序列化数据:原代码仅返回状态码,未按要求返回
SubscriptionSerializer序列化后的内容。 - 删除逻辑缺失:原DELETE分支仅返回状态码,未实际删除对应订阅记录。
修复代码
1. 修复SubscriptionCreateSerializer
该序列化器仅用于创建订阅,无需接收请求体字段,调整如下:
class SubscriptionCreateSerializer(serializers.ModelSerializer): class Meta: model = Subscription fields = [] # 无需请求体数据,user和author由视图传入 def create(self, validated_data): # 实际执行订阅记录创建 return Subscription.objects.create(**validated_data)
2. 修复CustomUserViewSet的subscribe方法
补充删除逻辑、订阅去重检查,并返回SubscriptionSerializer序列化数据:
class CustomUserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = CreateUserSerializer @action( detail=True, methods=['post', 'delete'], permission_classes=[IsAuthenticated], ) def subscribe(self, request, *args, **kwargs): user = request.user author_pk = int(kwargs.get('pk')) author_to_subscribe = get_object_or_404(User, id=author_pk) if request.method == 'DELETE': # 实际删除对应订阅记录 Subscription.objects.filter(user=user, author=author_to_subscribe).delete() return Response(status=status.HTTP_204_NO_CONTENT) if user.pk == author_pk: return Response( data={"errors": "Cannot subscribe to yourself"}, status=status.HTTP_400_BAD_REQUEST ) # 检查是否已订阅,避免重复创建 if Subscription.objects.filter(user=user, author=author_to_subscribe).exists(): return Response( data={"errors": "Already subscribed to this author"}, status=status.HTTP_400_BAD_REQUEST ) # 验证并创建订阅 serializer = SubscriptionCreateSerializer(data={}) serializer.is_valid(raise_exception=True) subscription = serializer.save(user=user, author=author_to_subscribe) # 使用SubscriptionSerializer序列化并返回结果 response_serializer = SubscriptionSerializer(subscription, context={'request': request}) return Response( data=response_serializer.data, status=status.HTTP_201_CREATED # 创建资源使用201状态码更符合REST规范 )
3. 优化SubscriptionSerializer
原序列化器中的to_internal_value方法用于反序列化(处理请求数据),但该序列化器仅用于返回响应数据,删除该方法避免潜在报错:
class SubscriptionSerializer(serializers.ModelSerializer): email = serializers.EmailField(source='author.email') id = serializers.IntegerField(source='author.id') username = serializers.CharField(source='author.username') first_name = serializers.CharField(source='author.first_name') last_name = serializers.CharField(source='author.last_name') is_subscribed = serializers.BooleanField(default=True) recipes = serializers.SerializerMethodField() def get_recipes(self, obj): qs = obj.author.recipes.all() return RecipePublicSerializer(qs, many=True).data def to_representation(self, instance): representation = super().to_representation(instance) representation['recipes_count'] = instance.author.recipes.count() return representation class Meta: model = Subscription fields = ('email', 'id', 'username', 'first_name', 'last_name', 'is_subscribed', 'recipes',)
内容的提问来源于stack exchange,提问作者aleksander
相关产品推荐
相关产品推荐

