我想知道是否可以使用
action
装饰器定义额外的参数:
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
@action(methods=['post'], detail=True)
def follow(self, request, pk=None):
user = self.get_object()
target_user = ???
Follow.objects.create(user=user, target=target_user)
return Response(status=status.HTTP_204_NO_CONTENT)
我想要实现的是匹配以下路径:
api/users/{id}/follow/{target_id}
follow
操作将用于让 ID 为 id
的用户关注另一个 ID 为 target_id
的用户。
更新:
由于似乎无法传递额外的参数,所以现在我将数据作为要遵循的用户 ID 列表发布:
用于验证数据的序列化器:
class FollowSerializer(serializers.ModelSerializer):
user_ids = serializers.ListField(child=serializers.IntegerField(min_value=1), required=False, help_text='User target IDs')
行动:
@action(detail=True, methods=['post'])
def follow(self, request, pk=None):
user = self.get_object()
serializer = FollowSerializer(data=request.data)
if serializer.is_valid():
serializer.data['user_ids']
for user_id in user_ids:
target_user = User.objects.get(pk=user_id)
Follow.objects.create(user=user, target=target_user)
return Response(status=status.HTTP_204_NO_CONTENT)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
我的解决方案的问题是,在自动生成的文档页面上,我看到带有
UserSerializer
字段的表单。
更新2:
下面的技巧让自动生成的文档页面显示正确的形式:
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
def get_serializer_class(self):
if self.action == 'follow':
return FollowSerializer
else:
return UserSerializer
@action(methods=['post'], detail=True)
def follow(self, request, pk=None):
...
您可以通过 url 传递
target_id
,api/users/{id}/follow/{target_id}
,但您必须将视图更改为,class UserViewSet(viewsets.ModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
@action(methods=['post'], detail=True)
def follow(self, request, *args, **kwargs):
user = self.get_object()
target_user = int(kwargs['target_id'])
Follow.objects.create(user=user, target=target_user)
return Response(status=status.HTTP_204_NO_CONTENT)
并在 urls.py 中定义一个
单独的path()
为,urlpatterns = [
path('users/<int:pk>/follow/<int:target_id>/', UserViewSet.as_view({"post": "follow"}))
]
我的解决方案的问题是,在自动生成的文档页面上,我看到带有 UserSerializer 字段的表单。
来自文档:
装饰器还可以采用仅为路由视图设置的额外参数。例如:
这意味着任何可以用作类属性的东西也可以用作
@action()
的参数,包括 serializer_class
:
@action(methods=['post'], detail=True, serializer_class=FollowSerializer)
def follow(self, request, pk=None):
# ...
serializer = self.get_serializer(data=request.data)
# ...
这将导致自动生成的文档中出现正确的表单。
事实上,您可以接受额外的 kwargs,如下 DRF 3.13.x,无需接触路由器,简洁的 DRF:
@action(detail=True, methods=['delete'], url_name='media-delete',
url_path='delete_media/(?P<media_pk>[^/.]+)')
def delete_media(self, request, pk=None, media_pk=None):
# do your logic
return Response({}, status=status.HTTP_202_ACCEPTED)
这将自动覆盖默认路由器额外路由,以响应 @action 包装器和 ModelViewSet 注册的路由。
我不确定。查看文档,似乎 @action() 只接受 .get_extra_actions() 获得的特定操作列表
您可以直接使用目标的电子邮件/帐户名称/帐户 ID 作为关注目标,然后发布该数据吗?无论如何,这似乎是更简单的方法。
defapprove_quotation(self, request, pk=None): 引用 = self.get_object()
# Assuming QuotationStatus has a unique constraint on name field
status_instance = get_object_or_404(QuotationStatus, name='Approved')
quotation.status = status_instance
quotation.save()
serializer = self.get_serializer(quotation)
return Response(serializer.data)
我无法更新状态