使用Django REST Framework ModelViewSet创建时如何强制赋值并通用化逻辑?
解决方案
你可以通过抽象公共混入类的方式通用化该逻辑,所有需要该规则的ModelViewSet只需继承混入类即可,无需重复编写代码。
方案1:和原有逻辑完全兼容的实现
该方案完全复用你现有修改request.data的逻辑,同时兼容表单、JSON两类请求场景,避免不可变QueryDict报错:
from rest_framework import status from rest_framework.response import Response class ClientAutoAssignMixin: def create(self, request, *args, **kwargs): if not request.user.is_staff: # 处理DRF默认QueryDict不可变的特性 if hasattr(request.data, '_mutable'): request.data._mutable = True request.data['client'] = request.user.profil.client.pk if hasattr(request.data, '_mutable'): request.data._mutable = False serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
使用方式
让需要该逻辑的ModelViewSet优先继承该混入类即可,自定义的swagger装饰器可以直接写在子类中:
class CategoryProductViewSet(ClientAutoAssignMixin, viewsets.ModelViewSet): queryset = CategoryProduct.objects.all() serializer_class = CategoryProductSerializer @swagger_auto_schema(responses={201: CategoryProductSerializer}) def create(self, request, *args, **kwargs): return super().create(request, *args, **kwargs) # 其他业务视图集同理继承即可 class GoodsViewSet(ClientAutoAssignMixin, viewsets.ModelViewSet): queryset = Goods.objects.all() serializer_class = GoodsSerializer
方案2:更推荐的无侵入实现
如果不需要在序列化器校验阶段就拿到client字段值,更推荐在保存阶段注入参数,避免修改请求对象带来的副作用,代码更简洁:
class ClientAutoAssignMixin: def perform_create(self, serializer): if self.request.user.is_staff: serializer.save() else: serializer.save(client=self.request.user.profil.client.pk)
注意:采用该方案时,你需要将对应序列化器的
client字段设为read_only=True,或者关闭必填校验,避免普通用户提交请求时因缺少client字段触发校验失败。
内容的提问来源于stack exchange,提问作者darkvodka
相关产品推荐
相关产品推荐

