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

Django REST Framework按当前用户限制外键选择的问题求助

问题描述

我查了好多资料、试了好几种方法都没用,试过限制外键可选范围和用CurrentUserDefault。我的需求是根据当前用户限制provider的可选范围,毕竟每个用户都有自己的provider。写了下面的Serializer和View代码后,运行报错:

TypeError: Field 'id' expected a number but got CurrentUserDefault(),

Serializer代码

class RideSerializer(serializers.ModelSerializer):

    invoice = InvoiceSerializer(required=False)
    duration = serializers.ReadOnlyField()
    riding_duration = serializers.ReadOnlyField()
    heading_duration = serializers.ReadOnlyField()
    earning_per_km = serializers.ReadOnlyField()
    earning_per_minute = serializers.ReadOnlyField()
    provider = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.select_related(
            'driver_profile__team', 'company_profile__team').filter(
            Q(driver_profile__team__user=serializers.CurrentUserDefault()) |
            Q(Company_profile__team__user=serializers.CurrentUserDefault())),
        default=serializers.CurrentUserDefault())

    class Meta:
        model = Ride
        exclude = ['shift', ]
        read_only_fields = ['id', 'start_time', ]

View代码

class RideView(
        viewsets.GenericViewSet,
        mixins.UpdateModelMixin,
        mixins.RetrieveModelMixin,
        mixins.ListModelMixin,
        mixins.CreateModelMixin,):
    permission_classes = [IsDriver, ]
    serializer_class = RideSerializer
    http_method_names = ['post', 'patch', 'get']

    def get_queryset(self):
        return super().get_queryset().select_related(
            'shift', "invoice").filter(shift__driver=self.request.user.driver_profile)

    def create(self, request, *args, **kwargs):
        self.serializer = self.get_serializer(
            data=request.data, context={'request': request})
        return super().create(request, *args, **kwargs)
解决方案

报错原因

CurrentUserDefault()是用来给字段设置默认值的工具,不能直接塞到查询集的filter条件里。序列化器初始化查询集时,还未获取到请求上下文,无法将CurrentUserDefault()解析为当前用户对象,导致把它当成普通实例传入,自然触发类型错误。

修改步骤

要动态获取当前用户过滤provider范围,我们可以自定义PrimaryKeyRelatedField,重写它的get_queryset方法来访问请求上下文:

  1. 编写自定义字段类
from rest_framework import serializers
from django.db.models import Q

class UserFilteredPrimaryKeyRelatedField(serializers.PrimaryKeyRelatedField):
    def get_queryset(self):
        # 从上下文获取当前用户
        user = self.context['request'].user
        queryset = super().get_queryset()
        # 根据当前用户过滤provider可选范围
        return queryset.select_related(
            'driver_profile__team', 'company_profile__team'
        ).filter(
            Q(driver_profile__team__user=user) | 
            Q(company_profile__team__user=user)  # 原代码的Company_profile需改为小写,符合Django字段命名规范
        )
  1. 更新RideSerializer中的provider字段
class RideSerializer(serializers.ModelSerializer):

    invoice = InvoiceSerializer(required=False)
    duration = serializers.ReadOnlyField()
    riding_duration = serializers.ReadOnlyField()
    heading_duration = serializers.ReadOnlyField()
    earning_per_km = serializers.ReadOnlyField()
    earning_per_minute = serializers.ReadOnlyField()
    # 使用自定义字段类,基础查询集设为User.objects.all(),后续动态过滤
    provider = UserFilteredPrimaryKeyRelatedField(
        queryset=User.objects.all(),
        default=serializers.CurrentUserDefault()
    )

    class Meta:
        model = Ride
        exclude = ['shift', ]
        read_only_fields = ['id', 'start_time', ]
  1. 额外注意
  • 原代码中Q(Company_profile__team__user=...)的Company_profile需改为小写company_profile,否则Django会提示字段不存在。
  • 你的View中create方法已将request传入上下文,其他方法(如update)GenericViewSet会默认处理,无需额外修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:35:23