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

如何解决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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 02:54:22