【问题标题】:Django rest Bad RequestDjango 休息错误请求
【发布时间】:2018-04-17 17:33:09
【问题描述】:

我已经扩展了用户模型来存储用户配置文件相关信息:

class Profile(models.Model):
    user = models.OneToOneField(User, blank=True, on_delete=models.CASCADE, )
    name = models.CharField(max_length=50, blank=True, null = True, )
    age = models.IntegerField(blank=True, null = True, )
    EDUCATION_CHOICES = (
    ('VOC', 'Vocational'),  
    ('DPL', 'Diploma'),
    ('BCL', 'Bachelor'),
    ('MST', 'Master'),
    ('DOC', 'Doctor'),
    )
    education = models.CharField(blank=True, null = True, choices=EDUCATION_CHOICES, max_length=3, )
    short_story = models.TextField(blank=True, null = True, max_length=500)
    ROLE_CHOICES = (
    ('INT', 'Intern'),  
    ('WOR', 'Worker'),
    ('SUP', 'Supervisor'),  
    ('MAN', 'Manager'),
    )
    role = models.CharField(blank=True, null = True, choices=ROLE_CHOICES, max_length=3, )
    hobbies = models.TextField(blank=True, null = True, max_length=500)
    rational_thinker = models.NullBooleanField(blank=True, null = True, default=False)
    welcome_new_changes = models.NullBooleanField(blank=True, null = True, default=False)
    embrace_science = models.NullBooleanField(blank=True, null = True, default=False)
    if_social = models.NullBooleanField(blank=True, null = True, default=False)
    seek_latest_info = models.NullBooleanField(blank=True, null = True, default=False)
    exciting_about_job = models.TextField(blank=True, null = True, max_length=500)
    not_exciting_about_job = models.TextField(blank=True, null = True, max_length=500)
    aspiration = models.TextField(blank=True, null = True, max_length=500)

    @receiver(post_save, sender=User)
    def create_user_profile(sender, instance, created, **kwargs):
        if created:
            Profile.objects.create(user=instance)

    @receiver(post_save, sender=User)
    def save_user_profile(sender, instance, **kwargs):
        instance.profile.save()

它的序列化器:

class ProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = Profile
        fields = '__all__'

并查看:

@api_view(['GET', 'PUT', 'DELETE'])
def profile(request):
    """
    Get, udpate, or delete a specific profile
    """
    try:
        profile = Profile.objects.get(user=request.user.id)
        print(profile)
        print(request.data)
    except Profile.DoesNotExist:
        return Response(status=status.HTTP_404_NOT_FOUND)

    if request.method == 'GET':
        serializer = ProfileSerializer(profile)
        return Response(serializer.data)

    elif request.method == 'PUT':
        print('PUT called')
        serializer = ProfileSerializer(profile, data=request.data)
        if serializer.is_valid():
            print('Valid')
            serializer.save(user=request.user)
            return Response(serializer.data)
        else:
            print('Else')
            return Response(
                serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    elif request.method == 'DELETE':
        profile.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

创建用户时会自动创建配置文件。

当我发送部分填充的数据(即某些字段发送为空白)时更新配置文件时,我收到错误请求错误。用户应该只能填写他希望填写的字段,但不能全部填写。如果我用所有数据发出 PUT 请求,那么它是成功的。

为什么会这样?

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    通常 PUT 方法用于更新所有字段。 PATCH 方法用于部分更新。但是您可以通过在序列化程序中添加partial=True 来覆盖它。如果您仍想使用 PUT 进行部分更新,则将序列化程序设置为

    serializer = ProfileSerializer(profile, data=request.data, partial=True)

    将其应用于您的视图将如下所示:

    @api_view(['GET', 'PUT', 'DELETE'])
    def profile(request):
        """
        Get, udpate, or delete a specific profile
        """
        try:
            profile = Profile.objects.get(user=request.user.id)
        except Profile.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND)
    
        if request.method == 'GET':
            serializer = ProfileSerializer(profile)
            return Response(serializer.data)
    
        elif request.method == 'PUT':
            serializer = ProfileSerializer(profile, data=request.data, partial=True)
            # setting raise_exception=True in the serializer's is_valid method will raise exception on error. So you don't have implement extra logics
            serializer.is_valid(raise_exception=True)
            serializer.save(user=request.user)
            return Response(serializer.data)
    
        elif request.method == 'DELETE':
            profile.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
    

    【讨论】:

    • 感谢您的回答!我意识到问题的发生只是因为年龄领域。如果我不输入任何值,它将作为空白字符串而不是 null 发送,这会导致错误
    • 对于部分更新不要发送空值的字段。只需从请求中删除字段。您应该在序列化程序中使用partial=True 来仅验证请求的字段
    【解决方案2】:

    PUT 方法需要所有字段。如果您只想传递几个字段,请使用 PATCH 方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-01-30
      • 1970-01-01
      • 2017-09-16
      • 2016-11-11
      • 2020-10-27
      • 2016-07-14
      • 1970-01-01
      相关资源
      最近更新 更多