虽然回答这个问题已经有点晚了,但我想为那些可能感兴趣的人回答一下。
默认情况下,GET
和DELETE
是幂等的,因为唯一可能的响应状态要么是404
,要么是发送数据,但对于PUT
或者如果我们需要使任何POST请求成为幂等的,则不是这样。 对于PUT
来说,最常见的方法是验证输入数据。确保传递了模型的所有字段(包括id
),除非客户端收到了400 bad request
,这样即使传递了id,也没有人可以向数据库添加不想要的记录。另一种100%确保一切都是幂等的方法是,我们可以使用缓存将请求正文和用户的id作为哈希存储到缓存服务器中足够长的时间,例如:
# in views.py
# for DRF
import hashlib
from django.core.cache import cache
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class IdempotentView(APIView):
def put(self, req, pk, format=None):
key = hashlib.blake2b(
f"{req.user.username}, {req.body},{pk}".encode("utf-8")
).hexdigest()
is_cached = cache.get(key)
if is_cached :
return Response (req.body, status=status.HTTP_201_CREATED)
# preform the view commands then:
expiary = 60*60*3 # 3 hours
cache.set(key, 'True' , exp_date)
return Response (data, status=status.HTTP_201_CREATED)
hashlib.blake2b
这样的东西,而不是依赖于hash
,因为这样可以减少碰撞的机会。 - suayip uzulmez我相信以下帖子可以为这个主题提供一些启示:Django Rest Framework中的创建或更新(使用PUT)
引用:
class ResourceViewSet(viewsets.ModelViewSet):
"""
This endpoint provides `create`, `retrieve`, `update` and `destroy` actions.
"""
queryset = Resource.objects.all()
serializer_class = ResourceSerializer
def get_object(self):
if self.request.method == 'PUT':
resource = Resource.objects.filter(id=self.kwargs.get('pk')).first()
if resource:
return resource
else:
return Resource(id=self.kwargs.get('pk'))
else:
return super(ResourceViewSet, self).get_object()
但更优雅的解决方案还要检查权限 - 可以参考https://gist.github.com/tomchristie/a2ace4577eff2c603b1b