【问题标题】:Retrieving a single object of interest rather than Blog.objects.all() in django rest framework在 django rest 框架中检索单个感兴趣的对象而不是 Blog.objects.all()
【发布时间】:2021-08-13 17:34:44
【问题描述】:

我很喜欢在 Django/DRF 中使用 基于类的视图,而不是功能视图。但我认为我的数据库点击量大大增加,从而导致我的 API 变慢。例如:

我有一个端点,它更新或删除在 url 中发送 id 的关注对象。我的观点是这样的。

class UpdateOrderView(UpdateAPIView,DestroyAPIView):
    permission_classes = [IsAuthenticated]    
    queryset = Order.objects.all()
    serializer_class = OrderUpdateSerializer

    def perform_destroy(self, instance):
        instance.delete()

正如我们在上面看到的,我的查询集是 Order 表中的所有对象。如果我打印查询集,它会提供 Order 表中的所有对象,这会使其变慢。

我的网址是:

path('api/updateorder/<int:pk>',views.UpdateOrderView.as_view(),name ='api-updateorder'),

我怎样才能在此处使用 id 获取特定对象?

在功能视图中,我们可以做到这一点。

def Update_or_delete(request,pk)

但是,pk 在基于类的视图中无法识别。

我的序列化器:

class OrderUpdateSerializer(serializers.ModelSerializer):
    order_items = OrderItemUpdateSerializer(many=True)
    billing_details = BillingDetailsSerializer()

    class Meta:
        model = Order
        fields = ['id','ordered','order_status','order_items','total_price','billing_details']



    def update(self, instance, validated_data):
        # billing_details_data = validated_data.pop('billing_details', None)
        # order_items_data = validated_data.pop('order_items')

        #instance = super(OrderUpdateSerializer, self).update(instance,validated_data)
        #print(instance)
        instance.order_status = validated_data.get('order_status')
        instance.ordered = validated_data.get('ordered')

        #billing_details_logic

        billing_details_data = validated_data.pop('billing_details',None)
        if billing_details_data is not None:
            instance.billing_details.address = billing_details_data['address']
            instance.billing_details.save()


        #order_items_logic

        instance.save()
    #instance.order_items.clear()
    order_items_data = validated_data.pop('order_items')
    print(order_items_data)

   
    for order_item_data in order_items_data:
        oi, created = OrderItem.objects.update_or_create(
            id = order_item_data['id'],

            defaults={
                'quantity' : order_item_data['quantity'],
                'order_item_status': order_item_data['order_item_status']
            }

        )             
    instance.save()
    return super().update(instance,validated_data)

2。我的第二个问题是这个。

许多高级开发人员都喜欢在 Django Rest Framework 中使用 APIView 而不是使用基于通用类的视图,因为人们可以在 APIView 中编写自定义代码,而不是在 CBV 中。例如,所有 CRUD API 都可以集成到 APIView 下的单个 API 中。

上面的说法真的是真的吗??那么,我应该停止使用 CBV 并改用 APIView 吗?我需要一个明确的解释。

【问题讨论】:

  • 为该视图提供服务的 url 是什么? pk是其中的一部分吗?
  • 我已经在代码中添加了我的网址。是的,我将 pk 作为参数传递。
  • 显示 OrderUpdateSerializer(和 Order 模型)查询集不会减慢您的速度,因为您只处理单个对象(UpdateAPIViewDestroyAPIView 处理单个对象)跨度>
  • 如果我在查询集之后执行打印命令,它会打印所有对象,即我正在查询整个表并带上所有对象。不是吗?? @AbdulAzizBarkat
  • @Django-Rocks QuerySets 是 lazy 因此在实际需要之前不会进行数据库查询。由于您的视图仅处理单个对象,因此应在此查询集上调用 filterget 以仅获取相关对象,因此您可能会在序列化程序中显示 nested 对象,这会减慢您的速度下来。

标签: python django api django-rest-framework django-class-based-views


【解决方案1】:

“但是,pk 在基于类的视图中无法识别。”

事实并非如此。您可以像基于函数的视图一样捕获 url 参数。

在 django 的 url 中传递的参数被捕获并存储在 kwargs 类似字典的对象中,您可以在视图中访问 CLASS BASED 视图。只需调用

value = self.kwargs.get(key) 

value = self.kwargs['pk] 

在你的情况下。 如果您编写自己的 get/post 方法,则无需通过 kwargs 即可接受所需的参数。 例如

class ProcessRequest(APIview):
   def get(self, request, pk, *args, **kwargs):
      # do some work
      pass

【讨论】:

  • 您好@joel,在基于类的视图中无法识别自我。我必须再次定义一个函数。
【解决方案2】:

你可以使用 rest-framework APIView 类然后你可以按照下面的例子做任何你想做的事情:

class FooBarView(APIView):
    def delete(self, request, *args, **kwargs):
        obj_pk = kwargs.get('pk')
        queryset = FooBarModel.objects.filter(pk=obj_pk).first()
        serialized_data = FoobarSerializer(queryset)
        return Response(serialized_data)




class FoobarViewSet(
    viewsets.GenericViewSet,
):

    def get_serializer_class(self):
        return FoobarSerializer

    def get_serializer_context(self):
        return {"request": self.request, "args": self.args, "kwargs": self.kwargs}

    def get_queryset(self):
        obj_id = self.kwargs.get('pk')

        queryset = Foobar.objects.filter(pk=obj_id)
        return queryset

对于第二个问题,您实际上也可以在 Serializer 中编写自定义代码。有时使用 ViewSets 更有意义,有时使用 APIView。 这取决于您正在处理的任务。

【讨论】:

    【解决方案3】:

    为什么不使用 DRF 路由器进行 url 路由? Routers

    这个路由器类有很多很好的特性来处理不同的端点,包括在需要的情况下提取 pk。

    【讨论】:

    • 我不喜欢使用视图集和模型视图集。我喜欢使用基于类的视图。谢谢
    猜你喜欢
    • 2018-07-14
    • 2021-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-29
    • 2011-08-10
    相关资源
    最近更新 更多