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。
修复步骤
修正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)修正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)优化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
相关产品推荐
相关产品推荐

