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

Django DRF中使用PATCH请求无法将Boolean字段更新为False

问题背景

你定义的Profile模型代码如下:

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    city = models.CharField(max_length=50, blank=True)
    country = models.CharField(max_length=50, blank=True)
    bio = models.CharField(max_length=500, blank=True)
    profile_pic = models.ImageField(upload_to='profile/%Y/%m/%d', default='media/placeholder.png', blank=False,
                                    null=False)
    is_online = models.BooleanField(default=False)
    is_active = models.BooleanField(default=False)

你需要实现一个仅通过PATCH方法更新is_active字段的API接口,最初编写的视图调整后如下:

class UpdateProfileActive(generics.UpdateAPIView):
    queryset = User.objects.all()
    serializer_class = UpdateUserSerializer

class UpdateProfileActive(generics.UpdateAPIView):
    queryset = User.objects.all()
    serializer_class = UpdateUserSerializer

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data='profile.is_active', partial=True)

        if serializer.is_valid():
            serializer.save()
            return Response({"message": "user is active field has been updated"})
        else:
            return Response({"message": "failed", "details": serializer.errors})

对应序列化器代码:

class UpdateUserSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(required=False)
    city = serializers.CharField(source='profile.city', allow_blank=True, required=False)
    country = serializers.CharField(source='profile.country', allow_blank=True, required=False)
    profile_pic = Base64ImageField(source='profile.profile_pic', max_length=None, use_url=True, required=False)
    is_online = serializers.BooleanField(source='profile.is_online', required=False)
    is_active = serializers.BooleanField(source='profile.is_active', required=False)

    class Meta:
        model = User
        fields = ['username', 'email', 'password', 'first_name', 'last_name', 'city', 'country', 'profile_pic', 'is_online', 'is_active']
        extra_kwargs = {'username': {'required': False},
                        'email': {'required': False},
                        'password': {'required': False},
                        'first_name': {'required': False},
                        'last_name': {'required': False},
                        'city': {'required': False},
                        'country': {'required': False},
                        'profile_pic': {'required': False},
                        'is_online': {'required': False},
                        'is_active': {'required': False},
                        }
    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile', {})
        city = profile_data.get('city')
        country = profile_data.get('country')
        profile_pic = profile_data.get('profile_pic')
        is_online = profile_data.get('is_online')
        is_active = profile_data.get('is_active')

        instance = super(UpdateUserSerializer, self).update(instance, validated_data)

        profile = instance.profile
        if profile_data:
            if city:
                profile.city = city
            if country:
                profile.country = country
            if profile_pic:
                profile.profile_pic = profile_pic
            if is_online:
                profile.is_online = is_online
            if is_active:
                profile.is_active = is_active
            profile.save()
        return instance

当前故障现象:向接口发送请求体{"is_active": false}时,is_active字段仍然保持原值True无法更新,但将字段设为True时可以正常生效。

故障原因

问题出在两处代码逻辑错误:

  1. 视图层传参完全错误:你在实例化序列化器时,给data参数传入了字符串'profile.is_active',而不是请求携带的实际数据request.data,序列化器根本无法获取到请求传入的is_active值。另外你重复定义了两次同名的UpdateProfileActive类,属于冗余代码。
  2. 序列化器更新逻辑的真值判断错误:你在更新Profile字段时使用了if is_active:这类判断,Python中False、空字符串''、None都属于假值,当你传入is_active=False时,判断条件不成立,赋值逻辑根本不会执行,自然无法将字段更新为False。同理is_online=False、city=''这类假值更新都会失效。
修复方案

1. 修正视图代码

删除重复的类定义,将序列化器的data参数改为请求数据,修正后代码:

from rest_framework import generics, Response

class UpdateProfileActive(generics.UpdateAPIView):
    queryset = User.objects.all()
    serializer_class = UpdateUserSerializer
    http_method_names = ["patch"] # 仅允许PATCH请求,符合接口设计需求

    def update(self, request, *args, **kwargs):
        instance = self.get_object()
        # 原代码此处传了字符串,改为传入请求实际数据
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response({"message": "user is_active field has been updated"})

2. 修正序列化器更新逻辑

去掉对字段值的真值判断,改为判断字段是否存在于待更新数据中,避免False、空字符串等合法假值被跳过:

def update(self, instance, validated_data):
    profile_data = validated_data.pop('profile', {})
    instance = super().update(instance, validated_data)

    profile = instance.profile
    need_update = []
    # 遍历所有Profile关联字段,只要传入了就更新,不管值是真还是假
    for field in ["city", "country", "profile_pic", "is_online", "is_active"]:
        if field in profile_data:
            setattr(profile, field, profile_data[field])
            need_update.append(field)
    if need_update:
        profile.save(update_fields=need_update) # 只更新传入的字段,提升性能
    return instance

额外注意

发送请求时需要使用标准JSON格式:

  • 布尔值使用小写的true/false,不要用Python语法的True/False
  • 请求头携带Content-Type: application/json,否则DRF可能无法正确解析请求体数据。

内容的提问来源于stack exchange,提问作者Emm

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 22:21:36