DRF POST接口无法保存Product:提示用户已存在错误
DRF添加产品接口提示“用户已存在”无法保存的解决方法
问题描述
使用Django Rest Framework开发添加产品的POST接口时,传入包含已有用户信息的JSON数据,serializer.is_valid()返回false,提示“用户已存在”,无法将Product保存到数据库。但通过Django管理后台可以正常为该用户创建产品。
相关代码如下:
views.py
@api_view(['POST']) def addProduct(request): serializer = ProductSerializer(data = request.data) if serializer.is_valid(): print("valid!!!") serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py(原代码)
from rest_framework import serializers from django.contrib.auth.models import User from products.models import Product from userProfile.serializers import UserSerializer class ProductSerializer(serializers.ModelSerializer): user = UserSerializer() class Meta: model = Product fields = "__all__"
Product模型
class Product(models.Model): uuid = models.CharField(max_length=100) product_name = models.CharField(max_length=50) model = models.CharField(max_length=30) date_of_purchase = models.DateField() description = models.TextField() user = models.ForeignKey(User, on_delete=models.CASCADE) defects = models.CharField(max_length=500) price = models.IntegerField(default=100) slug = models.SlugField(max_length=200) def save(self, *args, **kwargs): self.slug = slugify(self.uuid) super(Product, self).save(*args, **kwargs) def __str__(self): return f"{self.product_name}"
UserSerializer
from rest_framework import serializers from django.contrib.auth.models import User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['username','first_name', 'last_name','email','date_joined','is_staff','is_active']
传入的JSON数据
{ "id": 4, "user": { "username": "Anirudh", "first_name": "", "last_name": "", "email": "email@email.com", "date_joined": "2023-06-15T15:15:57.138400Z", "is_staff": true, "is_active": true }, "uuid": "qwerty", "product_name": "Phone", "model": "iPhone 12 mini 64GB", "date_of_purchase": "2021-08-15", "description": "Working condition, no dents. all buttons work. Upgrading to new phone so I am selling", "defects": "None", "price": 20000, "slug": "qwerty" }
原因分析
原代码中ProductSerializer使用了嵌套的UserSerializer(),DRF默认会将嵌套序列化器的逻辑处理为创建新的关联对象。也就是说,当你传入完整的用户信息时,DRF尝试创建一个新的User实例,但该用户的username或email已经存在于数据库中,触发了User模型的唯一约束,导致is_valid()校验失败,提示“用户已存在”。
而Django管理后台是通过选择已有用户的主键来关联,并非创建新用户,所以不会出现这个问题。
解决方案
方法一:使用主键关联(推荐)
直接通过用户ID关联已有用户,不需要传入完整用户信息,修改ProductSerializer:
from rest_framework import serializers from django.contrib.auth.models import User from products.models import Product class ProductSerializer(serializers.ModelSerializer): # 改为PrimaryKeyRelatedField,指定查询集 user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all()) class Meta: model = Product fields = "__all__"
对应的JSON数据可以简化为:
{ "id": 4, "user": 4, // 替换为实际存在的用户ID "uuid": "qwerty", "product_name": "Phone", "model": "iPhone 12 mini 64GB", "date_of_purchase": "2021-08-15", "description": "Working condition, no dents. all buttons work. Upgrading to new phone so I am selling", "defects": "None", "price": 20000, "slug": "qwerty" }
方法二:自定义create方法关联已有用户
如果业务需求必须传入完整用户信息,可以重写序列化器的create方法,手动获取已有用户并关联:
from rest_framework import serializers from django.contrib.auth.models import User from products.models import Product from userProfile.serializers import UserSerializer class ProductSerializer(serializers.ModelSerializer): user = UserSerializer() class Meta: model = Product fields = "__all__" def create(self, validated_data): # 取出用户数据 user_data = validated_data.pop('user') # 通过username获取已有用户(可根据实际情况用email等唯一字段) user = User.objects.get(username=user_data['username']) # 创建Product并关联用户 product = Product.objects.create(user=user, **validated_data) return product
注意:如果使用这种方法,需要确保传入的用户信息能唯一匹配到数据库中的用户,否则会抛出
User.DoesNotExist异常,可根据需求添加异常处理逻辑。
内容的提问来源于stack exchange,提问作者Aayanam Anirudh
相关产品推荐
相关产品推荐

