如何在Django Rest Framework中添加基于UUID的产品查询端点
当然能用@action()装饰器搞定!只是默认生成的URL确实不符合你的需求,不过咱们可以通过调整它的参数来定制路径,另外也给你准备了自定义路由的方案,两种方法都给你详细说说:
方案一:使用@action()装饰器实现
直接在你的ProductViewSet里新增一个action方法,通过指定url_path参数来定义你想要的URL结构,代码示例如下:
from rest_framework import viewsets, mixins from rest_framework.decorators import action from rest_framework.response import Response from .models import Product from .serializers import ProductSerializer class ProductViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Product.objects.all() serializer_class = ProductSerializer # 保留原有的通过ID查询的逻辑(不写也会继承RetrieveModelMixin的retrieve方法,写出来更清晰) def retrieve(self, request, *args, **kwargs): return super().retrieve(request, *args, **kwargs) # 新增通过UUID查询的action方法 @action(detail=False, methods=['get'], url_path='uuid/(?P<product_uuid>[^/.]+)') def get_by_uuid(self, request, product_uuid=None): try: # 根据UUID查询产品 product = self.queryset.get(uuid=product_uuid) serializer = self.get_serializer(product) return Response(serializer.data) except Product.DoesNotExist: return Response({"detail": "Product not found."}, status=404)
这里需要注意几个关键点:
detail=False:因为这个action不是基于默认的pk参数(原retrieve方法是detail=True,对应/products/{pk}),我们的自定义路径已经包含了product_uuid参数,所以要设为False。url_path里的正则表达式:(?P<product_uuid>[^/.]+)用来匹配UUID字符串,确保不会误匹配路径中的斜杠或点符号。- 方法里通过
product_uuid参数获取前端传入的UUID值,然后执行查询逻辑。
方案二:自定义路由配置(更灵活的方式)
如果你觉得用action的方式不够直观,也可以直接在URL配置里添加自定义的路由规则,这种方式更贴近传统Django的URL配置习惯:
首先在你的urls.py里添加自定义路由:
from django.conf.urls import url, include from rest_framework.routers import DefaultRouter from .views import ProductViewSet router = DefaultRouter() router.register(r'products', ProductViewSet) # 添加通过UUID查询的自定义路由 urlpatterns = [ url(r'^', include(router.urls)), url(r'^products/uuid/(?P<product_uuid>[^/.]+)/$', ProductViewSet.as_view({'get': 'retrieve_by_uuid'}), name='product-by-uuid'), ]
然后在ProductViewSet里新增对应的处理方法:
class ProductViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): queryset = Product.objects.all() serializer_class = ProductSerializer # 新增通过UUID查询的方法 def retrieve_by_uuid(self, request, product_uuid=None): try: product = self.queryset.get(uuid=product_uuid) serializer = self.get_serializer(product) return Response(serializer.data) except Product.DoesNotExist: return Response({"detail": "Product not found."}, status=404)
这种方式适合对路由结构有更精细控制的场景,逻辑拆分也更清晰。
两种方案都能完美满足你的需求,你可以根据自己的习惯来选择:用@action()的话,所有逻辑都封装在视图集里,符合DRF的视图集设计理念;自定义路由则更灵活,适合复杂的URL场景。
内容的提问来源于stack exchange,提问作者anttikoo
相关产品推荐
相关产品推荐

