如何解决Django创建Offer时出现的「字段必须唯一」错误?
问题:Vue+Django提交Offer数据触发用户唯一性约束错误
场景说明
开发Vue+Django应用时,通过Serializer提交Offer数据时收到错误:{"user":["Values of field must be unique."]},相关代码如下:
models.py
from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) class Order(models.Model): name = models.CharField(max_length=255) posted_by = models.ForeignKey(Profile, on_delete=models.CASCADE) class Offer(models.Model): order_related = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='offers') author = models.ForeignKey(Profile, on_delete=models.CASCADE)
serializers.py
class ProfileSerializer(serializers.ModelSerializer): class Meta: model = Profile fields = ("user",) class OfferSerializer(serializers.ModelSerializer): author = ProfileSerializer() class Meta: model = Offer fields = ("id", "order_related", "author") class OrderSerializer(serializers.ModelSerializer): posted_by = ProfileSerializer() class Meta: model = Order fields = ("id", "posted_by", "name")
views.py
class OfferView(ListModelMixin, GenericAPIView, CreateModelMixin): queryset = Offer.objects.all() serializer_class = OfferSerializer def post(self, request, *args, **kwargs): return self.create(request, *args, **kwargs)
前端Axios请求
const formData = { order_related: this.$route.params.order_id, author: {user: localStorage.getItem("user")}, } axios.post("api/v1/offers/", formData)
需求
在不修改AbstractUser模型、不额外请求获取Profile详情的前提下解决该问题。
解决方案
错误原因是当前OfferSerializer嵌套使用ProfileSerializer,提交数据时会尝试新建Profile实例,但该User对应的Profile已存在,触发了OneToOneField的唯一性约束。以下两种方案均可满足需求:
方案一:重写OfferSerializer的create方法
无需修改前端请求,直接在序列化器中处理传入的userID,关联到已存在的Profile:
class OfferSerializer(serializers.ModelSerializer): author = ProfileSerializer() class Meta: model = Offer fields = ("id", "order_related", "author") def create(self, validated_data): # 提取前端传入的author.user数据 author_data = validated_data.pop('author') user_id = author_data.get('user') # 通过user_id获取已存在的Profile实例 profile = Profile.objects.get(user_id=user_id) # 创建Offer并关联Profile offer = Offer.objects.create(author=profile, **validated_data) return offer
方案二:新增仅写字段接收User ID
在序列化器中新增一个仅用于写入的字段,直接接收userID并关联到Profile,同时调整前端请求字段:
后端修改serializers.py
class OfferSerializer(serializers.ModelSerializer): author = ProfileSerializer(read_only=True) # 仅用于序列化输出 # 新增仅写字段,接收User ID并关联到Profile的user字段 author_user_id = serializers.PrimaryKeyRelatedField( queryset=User.objects.all(), source='author.user', write_only=True ) class Meta: model = Offer fields = ("id", "order_related", "author", "author_user_id")
前端修改请求数据
const formData = { order_related: this.$route.params.order_id, author_user_id: localStorage.getItem("user"), } axios.post("api/v1/offers/", formData)
内容的提问来源于stack exchange,提问作者ILYASEM
相关产品推荐
相关产品推荐

