Django ModelSerializer用模型对象遇约束错误,如何实现用户订阅厨师接口?
问题分析与修复方案
核心错误原因
你遇到的NOT NULL constraint failed错误,本质是序列化器没有向数据库传递chef和customer的外键值,具体问题出在这几点:
- 最初使用的
SerializerMethodField是只读字段,仅用于序列化输出(比如返回订阅列表时展示厨师/用户信息),完全不参与反序列化(创建订阅)的流程,导致validated_data里没有这两个字段,调用save()时无法写入数据库。 - 后续修改
__init__直接赋值模型实例的方式也无效,因为ModelSerializer的字段逻辑是处理数据流转,直接赋值实例不会被加入validated_data,创建时依然缺失必填字段。
修复方案
第一步:简化序列化器
序列化器只负责输出订阅详情(展示厨师和用户的信息),创建订阅的逻辑交给视图处理:
class SubscriptionSerializer(serializers.ModelSerializer): # 用你已有的厨师/用户序列化器输出详情,标记为只读 chef = ChefListSerializer(read_only=True) customer = CustomerSerializer(read_only=True) class Meta: model = Subscription fields = ["id", "chef", "customer"]
第二步:修正视图逻辑
在视图的perform_create方法中,直接从URL参数和当前登录用户获取chef和customer实例,传递给序列化器的save()方法:
from django.shortcuts import get_object_or_404 class CustomerSubscribeChefView(viewsets.ModelViewSet): permission_classes = (permissions.IsAuthenticated,) serializer_class = SubscriptionSerializer queryset = Subscription.objects.all() def get_queryset(self): # 只返回当前用户的订阅记录 return self.request.user.subscription_set.all() def perform_create(self, serializer): # 从URL获取厨师ID,不存在则返回404 chef = get_object_or_404(Chef, pk=self.kwargs['chef_id']) # 直接传递chef和当前用户给save方法 serializer.save(chef=chef, customer=self.request.user) def create(self, request, *args, **kwargs): # 创建时不需要请求体数据,直接初始化序列化器 serializer = self.get_serializer() self.perform_create(serializer) return Response( {"msg": "Chef is subscribed!"}, status=status.HTTP_201_CREATED ) def get_object(self): # 确保删除的是当前用户订阅该厨师的记录,避免误删 return get_object_or_404(self.get_queryset(), chef_id=self.kwargs['chef_id']) def destroy(self, request, *args, **kwargs): instance = self.get_object() self.perform_destroy(instance) return Response({"msg": "Chef is unsubscribed!"}, status=status.HTTP_200_OK)
额外说明
如果需要让序列化器支持从请求体接收外键ID(比如特殊场景),可以添加write_only的外键字段:
class SubscriptionSerializer(serializers.ModelSerializer): chef = ChefListSerializer(read_only=True) customer = CustomerSerializer(read_only=True) # 仅用于写入的外键ID字段 chef_id = serializers.IntegerField(write_only=True) customer_id = serializers.IntegerField(write_only=True) class Meta: model = Subscription fields = ["id", "chef", "customer", "chef_id", "customer_id"]
此时视图的perform_create可以简化为:
def perform_create(self, serializer): serializer.save(chef_id=self.kwargs['chef_id'], customer_id=self.request.user.id)
内容的提问来源于stack exchange,提问作者Ali Ibrahim
相关产品推荐
相关产品推荐

