如何在Django REST Framework同一类的不同请求中使用不同lookup字段
DRF 不同请求匹配不同lookup字段实现方案
核心逻辑
默认SimpleRouter只会为ModelViewSet生成统一lookup字段的路由规则,要实现不同请求用不同lookup字段,需要同时修改路由规则和视图动态切换lookup字段两个部分。
第一步:视图层动态切换lookup字段
重写get_object方法,根据请求方法切换对应的lookup字段:
from rest_framework.viewsets import ModelViewSet from .models import User from .serializers import UserSerializer class UserViewSet(ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer # 默认lookup字段用id,适配更新、查询等请求 lookup_field = "id" def get_object(self): # 删除请求时切换为creation_date作为查询字段 if self.request.method == "DELETE": self.lookup_field = "creation_date" return super().get_object()
注意:需要保证
creation_date字段全局唯一,否则删除时会匹配到多个对象抛出异常,建议给该字段添加唯一约束,若为datetime类型需确保精度足够不会重复。
第二步:自定义SimpleRouter添加专属路由
默认Router的detail路由共用同一个路径参数,需要自定义Router为删除操作单独配置带creation_date参数的路由:
from rest_framework.routers import SimpleRouter, Route, DynamicRoute class CustomUserRouter(SimpleRouter): routes = [ # 列表路由保持默认 Route( url=r"^{prefix}{trailing_slash}$", mapping={"get": "list", "post": "create"}, name="{basename}-list", detail=False, initkwargs={"suffix": "List"} ), # 单独配置删除操作路由,参数为creation_date Route( url=r"^{prefix}/(?P<creation_date>[^/.]+){trailing_slash}$", mapping={"delete": "destroy"}, name="{basename}-destroy", detail=True, initkwargs={"suffix": "Destroy"} ), # 其他详情操作(查询、全量更新、部分更新)用id作为参数 Route( url=r"^{prefix}/(?P<id>[^/.]+){trailing_slash}$", mapping={"get": "retrieve", "put": "update", "patch": "partial_update"}, name="{basename}-detail", detail=True, initkwargs={"suffix": "Instance"} ), # 动态路由保持默认配置 DynamicRoute( url=r"^{prefix}/{url_path}{trailing_slash}$", name="{basename}-{url_name}", detail=False, initkwargs={} ), DynamicRoute( url=r"^{prefix}/(?P<id>[^/.]+)/{url_path}{trailing_slash}$", name="{basename}-{url_name}", detail=True, initkwargs={} ) ] # 注册路由 router = CustomUserRouter() router.register(r"user", UserViewSet, basename="user") urlpatterns = router.urls
可选优化
- 若
creation_date为datetime类型,可调整路由正则匹配规则适配ISO时间格式,比如将参数正则改为(?P<creation_date>\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z?) - 若多个视图需要类似逻辑,可将动态切换lookup字段的逻辑抽为公共Mixin,也可以将Router改为通用支持传入不同请求对应的lookup字段配置,减少重复代码。
内容的提问来源于stack exchange,提问作者Rackymuthu
相关产品推荐
相关产品推荐

