ev3*_*350 5 django django-rest-framework
我一直在为看板式项目板开发自己的 API。我附上了一个 UML 图来展示“boards”应用程序是如何组织的。
我的问题是,当我想创建一张新卡时,我希望能够创建带有在 POST 参数中传递的主键标签列表的卡,如下所示:
{
"title": "Test Card",
"description": "This is a Test Card!",
"created_by": 1,
"labels": [1,2]
}
Run Code Online (Sandbox Code Playgroud)
我的另一个要求是我想检索序列化标签作为卡片对象的一部分,如下所示:
{
"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": []
}
Run Code Online (Sandbox Code Playgroud)
我假设要实现 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."
]
}
]
}
Run Code Online (Sandbox Code Playgroud)
我在 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')
Run Code Online (Sandbox Code Playgroud)
视图.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)
Run Code Online (Sandbox Code Playgroud)
序列化器.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')
Run Code Online (Sandbox Code Playgroud)
如果有人遇到同样的问题,那么这就是解决方案。我认为您需要创建两个序列化器类,一个用于请求get,另一个用于请求post。viewset并从下面调用所需的序列化器,
class MyModelViewSet(viewsets.MyModelViewSet):
queryset = MyModel.objects.all()
serializer_class = MyModelSerializer # default serializer, you can change this to MyModelListSerializer as well
action_serializers = {
'list': MyModelListSerializer, # get request serializer
'create': MyModelCreateSerializer # post request serializer
}
def get_serializer_class(self):
if hasattr(self, 'action_serializers'):
return self.action_serializers.get(self.action, self.serializer_class)
return super(MyModelViewSet, self).get_serializer_class()
Run Code Online (Sandbox Code Playgroud)
MyModelListSerializer这是和的示例MyModelCreateSerializer,
# Used for the get request
class MyModelListSerializer(serializers.ModelSerializer):
assignees = AssigneesSerializer(read_only=True, many=True)
labels = LabelsSerializer(read_only=True, many=True)
class Meta:
model = MyModel
fields = '__all__'
# Used for the post request
class MyModelCreateSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = "__all__"
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3388 次 |
| 最近记录: |