(我是 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 引用也会有同样的问题),我做错了什么?
您可以通过为每个行为不同的“操作”提供单独的序列化器来实现此目的,并从
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