You need to enable JavaScript to run this app. 重写DRF ModelViewSet的create()方法时如何实现get_or_create逻辑?
优惠活动
大模型
产品
解决方案
定价
更多

重写DRF ModelViewSet的create()方法时如何实现get_or_create逻辑?

结论

无法直接替换perform_create实现需求,最优方案是遍历校验通过的提交数据,逐条调用get_or_create完成操作。


原因说明

  • DRF 原生的perform_create底层是调用序列化器的save()方法,在many=True的批量场景下默认执行批量INSERT操作,没有内置去重判断逻辑,直接替换方法不会产生幂等效果。
  • 你需要的「重复相同请求仅创建一次实例」的幂等能力,依赖业务层面的重复判断规则,只有逐条处理单条数据才能精准匹配判断规则,确认是否需要生成新实例。

实现示例

首先确认你用来判断实例重复的唯一字段,比如BayAccessToken用user_id+access_scene作为唯一判定条件,可参考如下修改代码:

from rest_framework import status
from rest_framework.response import Response

class CreateTokenView(viewsets.ModelViewSet):
    queryset = BayAccessToken.objects.all()
    serializer_class = accessTokenSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
        instances = []
        # 遍历校验后的有效数据逐条处理
        for item in serializer.validated_data:
            # 第一个参数填去重匹配字段,defaults填剩余需要写入/更新的字段
            instance, _ = BayAccessToken.objects.get_or_create(
                user_id=item.pop("user_id"),
                access_scene=item.pop("access_scene"),
                defaults=item
            )
            instances.append(instance)
        # 对齐原生返回格式
        return Response(
            self.get_serializer(instances, many=True).data,
            status=status.HTTP_201_CREATED
        )

优化建议

  • 建议先给BayAccessToken的去重字段加数据库层面的唯一约束(单字段唯一或联合唯一),避免并发请求下的竞态条件产生重复数据。
  • 如果单次请求提交的实例数量超过100条,可以先批量查询所有待匹配的去重字段值,过滤出不存在的条目后执行批量插入,减少数据库查询次数,性能优于逐条调用get_or_create。
  • 如果需要完全的接口级幂等(任意完全相同的请求体都仅执行一次),可以额外新增幂等令牌机制:要求请求头携带唯一的幂等ID,接口先校验幂等ID是否已经处理过,再执行业务逻辑,适配更严格的幂等场景。

内容的提问来源于stack exchange,提问作者Josh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 12:06:11