gpt4 book ai didi

Django Rest Framework POST 和 GET 嵌套序列化程序

转载 作者:行者123 更新时间:2023-12-03 23:15:52 30 4
gpt4 key购买 nike

我一直在为看板风格的项目板开发自己的 API。我附上了一张 UML 图来显示“板”应用程序是如何组织的。

My Application's Model UML Diagram

我的问题是,当我想创建一张新卡时,我希望能够通过在 POST 参数中传递的主键创建带有标签列表的卡,如下所示:

{
"title": "Test Card",
"description": "This is a Test Card!",
"created_by": 1,
"labels": [1,2]
}

我的另一个要求是我想检索序列化标签作为卡片对象的一部分,如下所示:
{
"id": 1,
"board": 1,
"title": "Some Card",
"description": "The description of Some Card.",
"created_by": 1,
"assignees": [
{
"id": 1,
"username": "test1",
"email": "test1_user@hotmail.co.uk"
}
],
"labels": [
{
"id": 1,
"board": 1,
"title": "Pink Label",
"color": "#f442cb"
}
],
"comment_set": []
}

我将假设要实现 POST 和 GET 功能的这种差异,我将不得不拥有 2 个不同的序列化程序?

然而,这篇文章的主要问题与上面提到的 POST 数据的创建逻辑有关。我不断收到这样的错误:
{
"labels": [
{
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
},
{
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
}
]
}

我在我的 CardSerializer 中尝试了许多不同的 DRF 序列化程序组合,但最终总是得到与上述格式相同的错误消息:“预期但得到”。任何帮助或指示,甚至有人告诉我这是糟糕的 REST 设计,例如,将不胜感激! :)

编辑:我应该补充一点,如果我将 CardSerializer 标签字段从 LabelSerializer 更改为 PrimaryKeyRelatedField (如代码中的注释所示),我收到以下错误:

禁止直接分配给多对多集合的前端。改用labels.set()。

以下是我的源代码的相关部分:

模型.py
class Card(models.Model):
"""Represents a card."""

# Parent
board = models.ForeignKey(Board, on_delete=models.CASCADE)
column = models.ForeignKey(Column, on_delete=models.CASCADE, null=True)

# Fields
title = models.CharField(max_length=255, null=False)
description = models.TextField()

assignees = models.ManyToManyField(User, blank=True, related_name='card_assignees')
labels = models.ManyToManyField(Label, blank=True, related_name='card_labels')

created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(blank=True, null=True) # Blank for django-admin

created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='card_created_by')

View .py
class CardList(generics.ListCreateAPIView):
queryset = Card.objects.all()
serializer_class = CardSerializer

def get_queryset(self):
columns = Column.objects.filter(board_id=self.kwargs['board_pk'])
queryset = Card.objects.filter(column__in=columns)
return queryset

def post(self, request, *args, **kwargs):
board = Board.objects.get(pk=kwargs['board_pk'])

post_data = {
'title': request.data.get('title'),
'description': request.data.get('description'),
'created_by': request.data.get('created_by'),
'assignees': request.data.get('assignees'),
'labels': request.data.get('labels'),
}
serializer = CardSerializer(data=post_data, context={'board': board})

if serializer.is_valid():
serializer.save()
return Response(serializer.data, status.HTTP_201_CREATED)
return Response(serializer.errors, status.HTTP_400_BAD_REQUEST)

serializers.py
class UserSerializer(serializers.ModelSerializer):
"""Serializer to map the User instance to JSON."""

class Meta:
model = User
fields = ('id', 'username', 'email')


class CommentSerializer(serializers.ModelSerializer):
"""Serializer to map the Comment instance to JSON."""

class Meta:
model = Comment
fields = '__all__'


class LabelSerializer(serializers.ModelSerializer):
"""Serializer to map the Label instance to JSON."""

class Meta:
model = Label
fields = ('id', 'board', 'title', 'color')


class CardSerializer(serializers.ModelSerializer):
"""Serializer to map the Card instance to JSON."""
assignees = UserSerializer(many=True, read_only=True)
labels = LabelSerializer(many=True)
comment_set = CommentSerializer(many=True, read_only=True)

# assignees = PrimaryKeyRelatedField(many=True, read_only=True)
# labels = PrimaryKeyRelatedField(many=True, queryset=Label.objects.all())

def create(self, validated_data):
board = self.context['board']
card = Card.objects.create(
board=board,
**validated_data
)
return card

class Meta:
model = Card
fields = ('id', 'board', 'title', 'description', 'created_by', 'assignees', 'labels', 'comment_set')
read_only_fields = ('id', 'board')

最佳答案

我设法找到了解决方案,但这可能不符合最佳实践。如果有人能澄清这一点,那就太好了。但是,就目前而言:

我将 CardSerializer 中的 create 函数更改为以下内容:

def create(self, validated_data):
board = self.context['board']
labels_data = validated_data.pop('labels')
card = Card.objects.create(
board=board,
**validated_data
)
card.labels.set(labels_data)
return card

card.labels.set(labels_data) 行表示我绕过以下错误消息:
Direct assignment to the forward side of a many-to-many set is prohibited.

这就是为什么我不确定这是否是“正确”的事情,但它现在似乎有效。

关于Django Rest Framework POST 和 GET 嵌套序列化程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50897691/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com