首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >我在Django REST框架view.py中修改了view.py。为什么我要在测试期间获得一个AttributeError,而不是使用实际的API使用呢?

我在Django REST框架view.py中修改了view.py。为什么我要在测试期间获得一个AttributeError,而不是使用实际的API使用呢?
EN

Stack Overflow用户
提问于 2022-04-20 02:17:09
回答 1查看 579关注 0票数 1

我的Django REST Framework正如期而至。在view.py中,我修改OrderViewSet,def partial_update,以便在将其保存到db之前向response.data dict添加另一个键/值对。当我用Postman调用API时,它可以正常工作。

但是,当我为相同的功能运行测试时,它会失败并返回:

代码语言:javascript
运行
复制
request.data["submission_date"] = datetime.now()
AttributeError: This QueryDict instance is immutable

如果在实际的API使用过程中没有发生这个错误,为什么在测试期间会出现这个错误呢?

View.py

代码语言:javascript
运行
复制
class OrderViewSet(viewsets.ModelViewSet):
    """ Includes custom PATCH functionality """
    queryset = Order.objects.all().order_by('-order_date')
    serializer_class = OrderSerializer
    authentication_classes = (authentication.TokenAuthentication,)
    permission_classes = [permissions.IsAuthenticated]

    def partial_update(self, request, *args, **kwargs):
        """ Update status and timestamp fields accordingly """
        status = request.data['status']

        if status == 'submitted':
            request.data["submission_date"] = datetime.now()

        if status == 'packaged':
            request.data["packaged_date"] = datetime.now()

        if status in ['sold', 'canceled', 'abandoned']:
            request.data["finished_date"] = datetime.now()

        return super().partial_update(request, *args, **kwargs)

Test.py

代码语言:javascript
运行
复制
def test_patch_order_status_from_cart_to_submitted(self):
    """ test patching order status from cart to submitted """
    order = sample_order(user=self.user)

    payload = {
        "status": "submitted"
    }

    res = self.client.patch(order_detail_url(order.id), payload)
    self.assertEqual(res.status_code, status.HTTP_200_OK)

    patched_order = Order.objects.get(id=order.id)
    self.assertEqual(patched_order.status, 'submitted')

def test_submitted_timestamp(self):
    """ test that patching order status to submitted also leaves timestamp """
    order = sample_order(user=self.user)

    payload = {
        "status": "submitted"
    }

    self.client.patch(order_detail_url(order.id), payload)

    patched_order = Order.objects.get(id=order.id)
    self.assertNotEqual(patched_order.submission_date, None)

编辑:

如果我要按下面的方式修改request.data的副本,那么如何从函数中返回它呢?

代码语言:javascript
运行
复制
    def partial_update(self, request, *args, **kwargs):
    """ Update status and timestamp accordingly """
    modified_data = request.data.copy()
    status = request.data['status']

    if status == 'submitted':
        modified_data["submission_date"] = datetime.now()

    if status == 'packaged':
        modified_data["packaged_date"] = datetime.now()

    if status in ['sold', 'canceled', 'abandoned']:
        modified_data["finished_date"] = datetime.now()

    return super().partial_update(request, *args, **kwargs)

解决方案:现在测试通过了。

views.py:

代码语言:javascript
运行
复制
    ...

    def partial_update(self, request, pk, *args, **kwargs):
        """ Update status and timestamp accordingly """
        order = Order.objects.get(id=pk)
        serializer = OrderSerializer(order, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

Serializers.py:

代码语言:javascript
运行
复制
class OrderSerializer(serializers.ModelSerializer):

    def update(self, order, validated_data):
        """ Update status and timestamp accordingly """
        status = validated_data.get('status')
        order.status = status
        if status == 'submitted':
            order.submission_date = datetime.now()
        elif status == 'packaged':
            order.packaged_date = datetime.now()
        elif status in ['sold', 'canceled', 'abandoned']:
            order.finished_date = datetime.now()

        order.save()
        return order

    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = ('id', 'user')
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-21 07:49:33

你是说修改request.data?我以前也有过这个错误。

然后我读了Django文档QueryDict,我想"request.data":

  • 是字典似的,不是字典。
  • 数据类型是不可变的。
  • 在修改之前复制它,比如: req_data = request.data.copy() req_data‘req_data_date’= datetime.now()

而在实际的API使用过程中出现错误的原因,可能只是在这种情况下不存在的状态。

另一方面,在本例中,我通常在modified_at或created_at DateTimeField中设置models.py,以便在修改或创建数据时自动记录submission_date。我觉得很方便。

代码语言:javascript
运行
复制
created_at = models.DateTimeField(auto_now_add=True, help_text="submission_date")
modified_at = models.DateTimeField(auto_now=True, help_text="re-submission_date")

编辑以获得另一个可能的解决方案,方法是使用ModelSerializer:

目的:我们要更新的数据不仅仅是基于request.data的直接。我们想使用其他一些逻辑:如果状态==‘提交’那么.

我认为submission_date,packaged_date,finished_date是有序模型的域。

views.py

代码语言:javascript
运行
复制
def partial_update(self, request, pk, *args, **kwargs):
    order = Order.objects.get(id=pk)
    serializer = OrderSerializer(order, data=request.data, partial=True)
    if serializer.is_valid():
        serializer.save()
        return Response(serializer.data)
    else:
        return Response(serializer.errors)

serializers.py

代码语言:javascript
运行
复制
class OrderSerializer(serializers.ModelSerializer):
    class Meta:
        model = Order
        fields = '__all__'

    def update(self, order, validated_data):
        status = validated_data.get('status')
        order.status = status
        if status == 'submitted':
            order.submission_date = datetime.now()
        elif status == 'packaged':
            order.packaged_date = datetime.now()
        elif status in ['sold', 'canceled', 'abandoned']:
            order.finished_date = datetime.now()

        order.save()
        return order
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71933383

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档