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

如何在DRF中无需提供ID即可获取并更新单例模型实例?

如何在DRF中无需提供ID即可获取并更新单例模型实例?

嗨,这个问题我之前也碰到过!单例模型确实不需要带ID,带ID反而显得多余,下面给你几个实用的解决办法:

方法一:改用APIView(最直接简单)

既然我们只需要处理单例的获取和更新,完全可以抛弃ViewSet,直接用APIView来写,这样路由可以直接绑定到/settings路径,不需要任何ID参数。

代码示例:

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

class GeneralSettingsAPIView(APIView):
    def get(self, request):
        # 直接获取单例实例
        settings = GeneralSettings.get_solo()
        serializer = GeneralSettingsSerializer(settings)
        return Response(serializer.data)
    
    def put(self, request):
        settings = GeneralSettings.get_solo()
        serializer = GeneralSettingsSerializer(settings, data=request.data)
        # 验证数据,不合法直接抛异常
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_200_OK)

然后路由配置不用router,直接加路径:

from django.urls import path

urlpatterns = [
    # 其他路由...
    path("settings/", GeneralSettingsAPIView.as_view(), name="api-settings"),
]

这样访问/api/settings就可以直接GET获取、PUT更新,完全不需要ID,逻辑也更清晰。

方法二:继续使用ViewSet,调整路由映射

如果你想继续保留ViewSet的结构(比如要复用一些通用逻辑),可以手动调整路由,把/settings直接映射到ViewSet的retrieve和update方法,同时保留你已经重写的get_object方法(这个方法写得很对,直接返回单例)。

首先你的ViewSet可以保持不变:

class GeneralSettingsViewSet(
    RetrieveModelMixin,
    UpdateModelMixin,
    GenericViewSet,
):
    queryset = GeneralSettings.objects.all()
    serializer_class = GeneralSettingsSerializer
    http_method_names = ["get", "put"]

    def get_object(self) -> GeneralSettings:
        return GeneralSettings.get_solo()

然后不要用router.register,而是手动添加路由:

from django.urls import path

urlpatterns = [
    # 其他路由...
    path(
        "settings/",
        GeneralSettingsViewSet.as_view({"get": "retrieve", "put": "update"}),
        name="api-settings"
    ),
]

这样/settings就会直接触发retrieve(GET)和update(PUT)动作,而因为你重写了get_object,不管有没有传入ID,都会返回单例实例,完美解决问题。

额外小提示

  • 你的queryset可以简化一下,比如写成GeneralSettings.objects.filter(pk=GeneralSettings.get_solo().pk),不过因为你已经重写了get_object,其实这个queryset对retrieve和update方法没有实际影响,只是DRF要求GenericViewSet必须有queryset属性而已。
  • 记得把http_method_names设置成["get", "put"],避免开放不必要的HTTP方法(比如delete,单例模型删了可就麻烦了)。

备注:内容来源于stack exchange,提问作者Ticoincoin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 18:44:27