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
相关产品推荐
相关产品推荐

