You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 03:57:19