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

Django REST Framework中使用关联字段作为lookup_field报错排查

问题:DRF通过username获取Profile时触发字段解析错误

我有一个User模型和用户注册时自动创建的Profile模型。在获取用户资料的视图中,我尝试通过username获取Profile,但DRF默认使用pk。于是我将lookup_field设置为username,但DRF无法解析,报错信息如下:

Cannot resolve keyword 'username' into field. Choices are: bio, created_at, id, image, updated_at, user, user_id

我的Profile模型

class Profile(TimeStampedModel):
    user = models.OneToOneField('User', on_delete=models.CASCADE, related_name='customer_profile')
    bio = models.TextField(blank=True)
    image = models.URLField(blank=True)
    
    def __str__(self):
        return self.user.username

我的Profile序列化器

class ProfileSerializer(serializers.ModelSerializer):
    username = serializers.StringRelatedField(source='user.username', read_only=True)
    bio = serializers.CharField(allow_blank=True, allow_null=True)
    image = serializers.SerializerMethodField()
    
    class Meta:
        model = Profile
        fields = ['username', 'bio', 'image']
        
    def get_image(self, obj):
        if obj.image:
            return obj.image
        
        return 'https://static.productionready.io/images/smiley-cyrus.jpg'

我的Profile获取视图

class ProfileRetrieveAPIView(generics.RetrieveAPIView):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer
    lookup_field = 'username'


    def retrive(self, request, username, *args, **kwargs):
        
        try:
            profile = Profile.objects.select_related('user').get(
                user__username = username
            )
        except Profile.DoesNotExist:
            ProfileDoesNotExist
        
        serializer = self.serializer_class(profile)
        
        return Response(serializer.data, status=status.HTTP_200_OK)

我的Profile接口路由

urlpatterns = [ 
    # ....
    path('profiles/<str:username>', views.ProfileRetrieveAPIView.as_view()),
]

错误原因分析

  1. lookup_field设置错误:Profile模型本身没有username字段,这个字段属于关联的User模型,直接设置lookup_field='username'会让DRF去Profile表中查找不存在的字段,导致报错。
  2. 方法名拼写错误:视图里的方法写成了retrive,正确的方法名是retrieve,这会导致DRF忽略你的自定义逻辑,走默认的查询流程,进一步触发lookup_field的错误。
  3. 异常处理无效:捕获Profile.DoesNotExist后,仅写了ProfileDoesNotExist,没有抛出异常或返回响应,会导致代码逻辑异常中断。

修复方案

方案一:利用DRF自带逻辑,修正lookup_field配置

from rest_framework import status
from rest_framework.response import Response

class ProfileRetrieveAPIView(generics.RetrieveAPIView):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer
    # 通过双下划线关联User模型的username字段
    lookup_field = 'user__username'
    # 指定URL中的参数名对应lookup_field的查询参数
    lookup_url_kwarg = 'username'

    # 修正方法名拼写
    def retrieve(self, request, *args, **kwargs):
        try:
            # 用DRF自带的get_object方法,结合lookup_field自动完成查询
            profile = self.get_object()
        except Profile.DoesNotExist:
            return Response({"detail": "用户资料不存在"}, status=status.HTTP_404_NOT_FOUND)
        
        serializer = self.serializer_class(profile)
        return Response(serializer.data, status=status.HTTP_200_OK)

方案二:保留自定义查询逻辑,移除错误的lookup_field

from rest_framework import status
from rest_framework.response import Response

class ProfileRetrieveAPIView(generics.RetrieveAPIView):
    queryset = Profile.objects.all()
    serializer_class = ProfileSerializer
    # 移除错误的lookup_field设置,完全使用自定义查询逻辑

    # 修正方法名拼写
    def retrieve(self, request, username, *args, **kwargs):
        try:
            profile = Profile.objects.select_related('user').get(
                user__username = username
            )
        except Profile.DoesNotExist:
            return Response({"detail": "用户资料不存在"}, status=status.HTTP_404_NOT_FOUND)
        
        serializer = self.serializer_class(profile)
        return Response(serializer.data, status=status.HTTP_200_OK)

路由保持不变

urlpatterns = [ 
    # ....
    path('profiles/<str:username>', views.ProfileRetrieveAPIView.as_view()),
]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 18:11:01