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

Django DRF端点正确却返回404:UpdateAPIView无法找到对象

问题:DRF UpdateAPIView返回404但手动可获取对象

用户的DRF相关代码如下,调用usersettings/<int:pk>/端点时返回404错误(提示"detail not found"),但通过断点手动查询能成功获取到对应对象,需排查原因并解决。

相关代码

URL定义

urlpatterns_usersettings = [
    path("usersettings/<int:pk>/", UpdateUserSettings.as_view())
]

视图类

class UpdateUserSettings(generics.UpdateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = UserSettingsSerializer
    def get_queryset(self):
        user = self.kwargs["pk"]
        return UserSettings.objects.all().filter(user=user)

模型定义

from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()

class UserSettings(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="user_settings")
    # ACCOUNT SETTINGS
    gotodash = models.BooleanField(default=False)
    loginalert = models.BooleanField(default=False)

    # DISPLAY SETTINGS
    darkmode = models.BooleanField(default=False)

    button_color = models.CharField(max_length=10, null=True, blank=True)
    link_color = models.CharField(max_length=10, null=True, blank=True)
    heading_color = models.CharField(max_length=10, null=True, blank=True)
    title_color = models.CharField(max_length=10, null=True, blank=True)
    tab_color = models.CharField(max_length=10, null=True, blank=True)

    created_at = models.DateTimeField(auto_now_add=True, verbose_name="created at")
    updated_at = models.DateTimeField(auto_now=True, verbose_name="updated at")

    class Meta:
        verbose_name = "user settings"
        verbose_name_plural = "users settings"
        db_table = "users_settings"

    def __str__(self):
        return f"{self.user}'s settings"

序列化器

from rest_framework import serializers
from .models import UserSettings
from django.contrib.auth import get_user_model
User = get_user_model()

class UserSettingsSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserSettings
        fields = "__all__"

问题原因

核心问题在于**UpdateAPIView的默认查找逻辑与你的get_queryset逻辑不匹配**:

  • UpdateAPIView继承自GenericAPIView,默认会使用URL中的pk参数去匹配目标模型(这里是UserSettings)自身的主键id,而不是关联的User的id。
  • 你的get_queryset是用URL的pk过滤UserSettings关联的User,但视图在执行查找时,会先从get_queryset返回的集合里,用默认的lookup_field(即pk,对应UserSettings.id)去匹配URL的pk值,自然找不到对应对象,返回404。

解决方案

提供两种可行的修正方式,按需选择:

方式一:重写get_object(推荐)

直接跳过视图默认的查找逻辑,手动获取对应UserSettings对象:

class UpdateUserSettings(generics.UpdateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = UserSettingsSerializer

    def get_object(self):
        # 场景1:用户只能修改自己的设置(更安全,无需URL传pk)
        # return UserSettings.objects.get(user=self.request.user)
        
        # 场景2:允许通过URL的pk指定用户修改(需额外做权限校验)
        user_id = self.kwargs["pk"]
        return UserSettings.objects.get(user_id=user_id)

如果用场景1,URL可以简化为path("usersettings/", UpdateUserSettings.as_view()),避免用户越权修改他人设置。

方式二:指定lookup_field

修改视图的查找字段为关联User的id,让视图用URL的pk去匹配UserSettings.user.id:

class UpdateUserSettings(generics.UpdateAPIView):
    permission_classes = [IsAuthenticated]
    serializer_class = UserSettingsSerializer
    lookup_field = 'user__id'  # 指定查找关联用户的id

    def get_queryset(self):
        return UserSettings.objects.all()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 22:10:00