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

DRF中POST创建新Beer对象关联已有对象报错问题

Django DRF创建Beer对象时关联已有BeerType/Brewery的问题及后续疑问

问题场景

我是Django和Django Rest Framework(DRF)新手,在通过POST请求创建新的Beer对象时,尝试关联已存在的BeerType和Brewery对象遇到了问题。

Beer模型定义

class Beer(models.Model):
    id = models.BigAutoField(primary_key=True)
    name = models.CharField(max_length=255)
    brewery = models.ForeignKey(Brewery, on_delete=models.CASCADE)
    beer_type = models.ForeignKey(BeerType, on_delete=models.PROTECT)

    class Meta:
        db_table = "beer"

BeerSerializer定义

class BeerSerializer(serializers.ModelSerializer):
    brewery = BrewerySerializer()
    beer_type = BeerTypeSerializer()

    class Meta:
        model = Beer
        fields = ['id', 'name', 'brewery', 'beer_type']

    def create(self, validated_data):
        brewery_data = validated_data.pop('brewery')
        beer_type_data = validated_data.pop('beer_type')
        beer = Beer.objects.create(**validated_data)
        beer.brewery = Brewery.objects.get_or_create(**brewery_data)
        beer.beer_type = BeerType.objects.get_or_create(**beer_type_data)
        return beer

BeerViewSet的create方法

class BeerViewSet(viewsets.GenericViewSet):
    permission_classes = [permissions.IsAuthenticated]
    serializer_class = BeerSerializer

...
    def create(self, request):
        pdb.set_trace()
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

POST请求数据

{
    "beer_type": {
        "id": 154,
        "name": "Beer Type 1"
    },
    "brewery": {
        "country": "c1",
        "id": 929,
        "location": "l1",
        "name": "Brewery1"
    },
    "name": "Beer1"
}

错误响应

{
    "beer_type": {
        "name": [
            "beer type with this name already exists."
        ]
    }
}

该BeerType确实已存在,但我希望创建新Beer对象时直接关联已有对象,请问哪里出错了?


更新1:修改后的代码

根据建议修改了序列化器:

class BeerSerializerGet(serializers.ModelSerializer):
    brewery = BrewerySerializer()

    class Meta:
        model = Beer
        fields = ['id', 'name', 'brewery', 'beer_type']
        depth = 1
        validators = []


class BeerSerializerCreate(BeerSerializerGet):
    brewery = PrimaryKeyRelatedField(queryset=Brewery.objects)

同时修改了ViewSet,通过传入的ID获取已有对象:

class BeerViewSet(viewsets.GenericViewSet):
    permission_classes = [permissions.IsAuthenticated]

    def list(self, request):
        queryset = Beer.objects.all()
        serializer_context = {'request': request}
        serializer = BeerSerializerGet(queryset, many=True, context=serializer_context)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = Beer.objects.all()
        beer = get_object_or_404(queryset, pk=pk)
        serializer_context = {'request': request}
        serializer = BeerSerializerGet(beer, context=serializer_context)
        return Response(serializer.data)

    def create(self, request):
        beerName = request.data['name']
        pdb.set_trace()
        breweryId = request.data['brewery_id']
        beerTypeId = request.data['beer_type_id']
        brewery = get_object_or_404(Brewery.objects.all(), pk=breweryId)
        beerType = get_object_or_404(BeerType.objects.all(), pk=beerTypeId)
        beer = Beer.objects.create(name = beerName, brewery=brewery, beer_type=beerType)
        serializer_context = {'request': request}
        serializer = BeerSerializerGet(beer, context=serializer_context)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

更新2:疑问

我发现上述代码并未使用两个不同的序列化器,仅使用了GET序列化器,由ViewSet处理关联对象的获取,请问这是否属于不良实践?还是一种可行的方案?


内容的提问来源于stack exchange,提问作者Svend Hansen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 19:24:52