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

Django嵌套序列化器中perform_create传入User对象而非ID引发类型错误的解决问询

Django嵌套序列化器中perform_create传入User对象而非ID引发类型错误的解决问询

问题描述

我在Django里给User模块和BookDetail模型用了嵌套序列化器,BookDetail里的user是外键字段。写perform_create方法的时候碰到了个错误——系统没使用用户ID,反而直接传了整个User对象(比如<User: Aditya@123>),导致类型转换失败。

下面是我的相关代码:

models.py

from django.db import models
from django.contrib.auth.models import User

class Book_Detail(models.Model):
    def nameFile(instance, filename):
        user = User.objects.get(username=instance.user_id)
        return '/'.join([str(user.username), filename])

    book_isbn = models.CharField(max_length=15)
    book_name = models.CharField(max_length=255)
    book_page = models.IntegerField()
    book_medium = models.CharField(max_length=20)
    book_author = models.CharField(max_length=255)
    book_genre = models.CharField(max_length=20)
    book_cover_page = models.ImageField(upload_to=nameFile, blank=True)
    book_last_page = models.ImageField(upload_to=nameFile, blank=True)
    book_page1 = models.ImageField(upload_to=nameFile, blank=True)
    book_page2 = models.ImageField(upload_to=nameFile, blank=True)
    book_page3 = models.ImageField(upload_to=nameFile, blank=True)
    book_rental = models.CharField(max_length=20, null=True, blank=True)
    book_price = models.FloatField()
    book_description = models.TextField(null=True, blank=True)
    status = models.CharField(max_length=45)
    posted_date = models.DateField(null=True)
    user = models.ForeignKey(to=User, on_delete=models.CASCADE, related_name='user')

serializers.py

from authentication.serializers import UserSerializer
from rest_framework.serializers import ModelSerializer
from .models import Book_Detail

class BookDetailsSerializer(ModelSerializer):
    user = UserSerializer(read_only=True)

    class Meta:
        model = Book_Detail
        fields = '__all__'

views.py

from .models import Book_Detail
from .serializers import BookDetailsSerializer
from rest_framework import permissions
from rest_framework.generics import ListCreateAPIView

class BookDetailsList(ListCreateAPIView):
    serializer_class = BookDetailsSerializer
    permission_classes = (permissions.IsAuthenticated,)

    def perform_create(self, serializer):
        serializer.save(user_id=self.request.user)

    def get_queryset(self):
        return Book_Detail.objects.filter(user_id=self.request.user)

错误信息

Internal Server Error: /api/sell/
Traceback (most recent call last):
File "C:\Users\Aditya Pandit\.virtualenvs\bookmart-ugZrwS1X\Lib\site-packages\django\db\models\fields\__init__.py", line 2018, in get_prep_value
return int(value)
^^^^^^^^^^
TypeError: int() argument must be a string, a bytes-like object or a real number, not 'User'

...(省略中间重复栈信息)

TypeError: Field 'id' expected a number but got <User: Aditya@123>.

我试了好几种方法想拿到用户ID,但每次得到的都是User对象,希望能在perform_create里正确传入User模型的ID值。


解决方案

错误根源

问题核心很简单:user_id字段需要的是整数类型的用户ID,但你传进去的是完整的User对象(self.request.user),Django没法把User对象直接转成整数,所以才抛出类型错误。另外你的get_queryset方法里也犯了同样的错,过滤时传的是User对象而非ID。

修复步骤

  1. 修正perform_create方法
    把user_id=self.request.user改成下面两种写法的任意一种:

    def perform_create(self, serializer):
        # 方式1:直接传User对象,Django会自动处理外键关联(推荐)
        serializer.save(user=self.request.user)
        # 方式2:明确传入用户ID
        # serializer.save(user_id=self.request.user.id)
    
  2. 修正get_queryset方法
    过滤时同样要传对参数,两种写法都可行:

    def get_queryset(self):
        # 方式1:直接用User对象过滤(直观易读)
        return Book_Detail.objects.filter(user=self.request.user)
        # 方式2:用用户ID过滤
        # return Book_Detail.objects.filter(user_id=self.request.user.id)
    
  3. 优化models.py里的nameFile方法
    你现在的nameFile方法里通过instance.user_id查用户,这里其实有问题——模型里的外键字段名是user,instance.user才是User对象,instance.user_id是对应的ID值,所以当前代码会报错,改成这样更高效:

    def nameFile(instance, filename):
        # 直接从实例的user属性获取用户,不用额外查数据库
        return '/'.join([str(instance.user.username), filename])
    

为什么这样能解决问题?

  • 当你传user=self.request.user时,Django的ORM会自动把User对象和外键字段关联起来,不用手动传ID。
  • 如果非要用user_id参数,就必须传整数类型的ID,也就是self.request.user.id或者self.request.user.pk(pk是主键的通用写法,更推荐)。

备注:内容来源于stack exchange,提问作者Kratos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 14:15:28