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

Django REST Framework的ModelSerializer因缺失user字段引发KeyError

解决ModelSerializer调用.data时的KeyError问题

问题场景

调用AuthTokenResponseSerializer的.data方法时触发KeyError,提示无法找到user字段,传入的数据中仅包含user_id键,而非Serializer期望的user键。

相关代码片段

AuthToken模型

class AuthToken(models.Model):

    objects = AuthTokenManager()

    digest = models.CharField(
        max_length=CONSTANTS.DIGEST_LENGTH, primary_key=True)
    token_key = models.CharField(
        max_length=CONSTANTS.TOKEN_KEY_LENGTH, db_index=True)
    user = models.ForeignKey(User, null=False, blank=False,
                             related_name='auth_token_set', on_delete=models.CASCADE)
    created = models.DateTimeField(auto_now_add=True)
    expiry = models.DateTimeField(null=True, blank=True)

    def __str__(self):
        return '%s : %s' % (self.digest, self.user)

自定义Serializer

class AuthTokenResponseSerializer(serializers.ModelSerializer):
    class Meta:
        model = AuthToken
        fields = "__all__"

错误信息

>>> token_serializer.data
*** KeyError: "Got KeyError when attempting to get a value for field `user` on serializer `AuthTokenResponseSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `dict` instance.
Original exception text was: 'user'."

传入的数据结构

AuthTokenResponseSerializer(context={'request': <rest_framework.request.Request: POST '/auth/token/'>, data={'_state': <django.db.models.base.ModelState object>, 'digest': '6b82ac8776113db376d8938a641c3ebdea573b4ab49cb648c171fccc7f4a517e6450cebb21682e26f36562cf7b659f5089957ba49e99c096ebc9eaaa93ab0e53', 'token_key': '872832f8', 'user_id': 34, 'created': None, 'expiry': datetime.datetime(2024, 5, 11, 9, 17, 2, 540546, tzinfo=datetime.timezone.utc)}, partial=True):
    digest = CharField(max_length=128, validators=[<UniqueValidator(queryset=AuthToken.objects.all())>])
    token_key = CharField(max_length=8)
    created = DateTimeField(read_only=True)
    expiry = DateTimeField(allow_null=True, required=False)
    user = PrimaryKeyRelatedField(queryset=User.objects.all())

User模型

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import (
    AbstractBaseUser,
    PermissionsMixin,
    BaseUserManager,
)
from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(
        verbose_name=_("email address"), unique=True, max_length=255
    )
    password = models.CharField(
        max_length=128, null=True
    ) 
    first_name = models.CharField(max_length=128, null=True)
    last_name = models.CharField(max_length=128, null=True)
    phone_number = PhoneNumberField(null=True, blank=True)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(default=timezone.now)
    updated_at = models.DateTimeField(default=timezone.now)

修复方案

方案1:修改传入数据的键名

在初始化Serializer前,将数据中的user_id重命名为user,直接传入用户ID即可:

# 假设原始数据存放在data变量中
data['user'] = data.pop('user_id')
token_serializer = AuthTokenResponseSerializer(data=data)

方案2:自定义Serializer字段映射

如果不想修改原始数据,可在Serializer中显式指定user字段的取值来源为user_id:

class AuthTokenResponseSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(
        queryset=User.objects.all(),
        source='user_id'
    )

    class Meta:
        model = AuthToken
        fields = "__all__"

若仅用于序列化输出,可将user字段设为只读,Serializer会自动关联用户实例:

class AuthTokenResponseSerializer(serializers.ModelSerializer):
    user = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = AuthToken
        fields = "__all__"

方案3:传入AuthToken模型实例而非字典

如果是从数据库获取的AuthToken对象,直接传入实例而非字典,Serializer会自动处理关联字段:

token_instance = AuthToken.objects.get(digest='xxx')
token_serializer = AuthTokenResponseSerializer(instance=token_instance)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 05:38:15