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()), ]
错误原因分析
- lookup_field设置错误:Profile模型本身没有
username字段,这个字段属于关联的User模型,直接设置lookup_field='username'会让DRF去Profile表中查找不存在的字段,导致报错。 - 方法名拼写错误:视图里的方法写成了
retrive,正确的方法名是retrieve,这会导致DRF忽略你的自定义逻辑,走默认的查询流程,进一步触发lookup_field的错误。 - 异常处理无效:捕获
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
相关产品推荐
相关产品推荐

