如何在ModelViewSet中获取super()。create()创建的模型?

时间:2019-05-28 20:35:52

标签: django django-rest-framework

我正在尝试在ModelViewSet的super().create()方法中获取由create()创建的模型的副本。最简单的方法是什么?

我有一个ModelViewSet,它接受通用的POST请求,我知道这很好,因为我最终在数据库中有了一条新记录。我要做的是获取刚刚创建的对象,以便将其pk返回给客户端。但是,以下操作无效:

class ItemViewSet(viewsets.ModelViewSet):
    model = Item
    # ...
    def create(self, request, *args, **kwargs):
        super().create(request, *args, **kwargs)  # Successfully creates instance
        instance = self.get_object()  # Throws error
        return Response({'status': 'success', 'pk': instance.pk})

与其他DRF ModelViewSet方法一样,我希望self.get_object()能为我创建实例,尽管通常只能在“详细途径”中使用。我得到的是以下错误: AssertionError: Expected view CultivarStockViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.

任何见识都受到赞赏!

3 个答案:

答案 0 :(得分:2)

通过进一步的调试,我弄清楚了。为了后代的缘故,这是我工作的create()方法:

def create(self, request, *args, **kwargs):
    response = super().create(request, *args, **kwargs)
    instance = response.data
    return Response({'status': 'success', 'pk': instance['pk']})

答案 1 :(得分:2)

由于Django使用参数执行过滤,因此您确实无法使用get_object [classy-doc]获取对象。实际上,get_object实现看起来像:

def get_object(self):
    # ...
    queryset = self.filter_queryset(self.get_queryset())

    # Perform the lookup filtering.
    lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field

    # ...

    filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
    obj = get_object_or_404(queryset, **filter_kwargs)

    # May raise a permission denied
    self.check_object_permissions(self.request, obj)

    return obj

这些self.kwargs不可用,因此get_object调用失败。

不过,我们可以修补create [classy-doc]函数并在此处使用serializer.instance [drf-doc]

class ItemViewSet(viewsets.ModelViewSet):
    model = Item
    # ...

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        return Response({'status': 'success', 'pk': serializer.instance.pk})

答案 2 :(得分:1)

我知道我很晚才回答这个问题。但是如果有人遇到这种问题,@JohnnyHammersticks 提供的答案效果很好。但问题是,此解决方案将创建对象两次(就我而言,我也有 perform_create 函数)。处理这种情况的最佳方法如下,

def create(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    self.perform_create(serializer)

    if serializer.is_valid():
        instance = serializer.data
        pk = data['id']
        return Response({'status': 'success', 'pk': instance['pk']})