DRF - 在 POST 上参考现有对象创建新对象

问题描述 投票:0回答:1

(我是 Django Rest Framework 和 Django 的新手)

我有一个啤酒模型,如下所示:

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

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)

(我省略了 ViewSet 中的

list
retrieve
实现)

当我使用以下 JSON 从我的应用程序向

/api/beers/
发出 POST 请求时:

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

我收到代码 400 和错误正文的错误:

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

这在技术上是正确的,但是如果我想允许 POST 创建一个新的 Beer 对象,该对象引用现有的 BeerType 对象(我想我对 Brewery 引用也会有同样的问题),我做错了什么?

django-rest-framework
1个回答
0
投票

您可以通过为每个行为不同的“操作”提供单独的序列化器来实现此目的,并从

get_serializer()
类返回该序列化器。

从使用默认行为的

create
序列化器开始。这将接受啤酒厂的 ID,所以
{"brewery": 1}

class BeerEditSerializer(ModelSerializer):
    class Meta:
        model = Beer
        fields = "__all__"

list
操作创建第二个序列化器。如果需要,您可以继承前一个,但我发现保持它们独立更安全。

class BeerViewSerializer(ModelSerializer):
    brewery = BrewerySerializer()
    beer_type = BeerTypeSerializer()

    class Meta:
        ....


在您看来,您现在可以根据请求所使用的 viewset 操作返回正确的值:

    def get_serializer_class(self):
        if self.action in ["create", "update", "partial_update", "delete"]:
            return BeerEditSerializer
        else:
            return BeerViewSerializer
© www.soinside.com 2019 - 2024. All rights reserved.