You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django ModelSerializer用模型对象遇约束错误,如何实现用户订阅厨师接口?

问题分析与修复方案

核心错误原因

你遇到的NOT NULL constraint failed错误,本质是序列化器没有向数据库传递chef和customer的外键值,具体问题出在这几点:

  1. 最初使用的SerializerMethodField是只读字段,仅用于序列化输出(比如返回订阅列表时展示厨师/用户信息),完全不参与反序列化(创建订阅)的流程,导致validated_data里没有这两个字段,调用save()时无法写入数据库。
  2. 后续修改__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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:15:30