Django Rest Framework ModelViewSet显式允许后POST方法仍未生效
问题场景
刚接触Django Rest Framework,以超级用户身份操作Item接口时,POST表单不显示且提示"POST方法不允许"。当前使用Django Guardian的BigGroup/BigUser权限框架,尝试多种配置方案后仍未解决,相关代码及尝试如下:
Model代码(model.py)
class Category(models.Model): category = models.CharField('category', max_length=100, null=False, blank=False, default="NA") def __str__(self) -> str: return self.category class Meta: verbose_name_plural = "categories" class Item(models.Model): name = models.CharField('name', max_length=64) slug = models.SlugField(max_length=64, null=True, blank=True) icon = models.ImageField(blank=True, upload_to ='uploads/') category = models.ForeignKey( Category, on_delete=models.CASCADE, default='Uncategorized') subcategory = models.CharField( max_length=255, null=True, blank=True) quantity = models.DecimalField( max_digits=9, decimal_places=2) suggested_value = models.DecimalField( max_digits=6, decimal_places=2, null=False) retail_value = models.DecimalField(max_digits=6, decimal_places=2,max_length=30) description = models.TextField('description', max_length=255, blank=True) created_at = models.DateTimeField(auto_now_add=True, db_index=True) tenant = models.TextField('tenant', default='shared') exclude = ('tenant') class Meta: # db_table = "storeItems_item" default_permissions = ('view','add', 'change', 'delete') ordering = ['name'] get_latest_by = 'created_at' def __str__(self): return self.name def get_absolute_url(self): return reverse( 'storeItems_item_detail', args=(), kwargs={'slug': self.slug}) def save(self, *args, **kwargs): # assign permission to item group = Group.objects.get(name=self.tenant) super(Item, self).save(*args, **kwargs) for perm in ['view_item', 'add_item','change_item']: assign_perm(perm, group, self) # Default retail value if not self.retail_value: self.retail_value = self.suggested_value() super().save(*args, **kwargs)
尝试过的ViewSet权限配置
class StoreItemsViewSet( viewsets.ModelViewSet, PermissionListMixin, # viewsets.GenericViewSet, mixins.ListModelMixin, # mixins.CreateModelMixin, mixins.UpdateModelMixin, ): queryset = Item.objects.all() serializer_class = StoreItemsSerializer # permission_classes = ( # BigGroupObjectPermission, BigUserObjectPermission) permission_classes = [ItemPermission] # @action(detail=True, methods=['post', 'delete']) # def perform_create(self, serializer): # serializer.save(owner=self.request.user) # def create(self, request, *args, **kwargs): # instance = super().create(request, *args, **kwargs) # assign_perm("change_item", request.user, instance) # assign_perm("change_item", request.user, instance) # return instance # def post(self, request): # return Response()
自定义全权限类尝试
class FullPermission(BasePermission): # def has_permission(self, request, view): # return request.method in SAFE_METHODS def has_permission(self, request, view): return True def has_object_permission(self, request, view, obj): return True
排查方向
- 验证权限类逻辑:先临时将
permission_classes替换为IsAdminUser或FullPermission,如果POST恢复正常,说明ItemPermission的has_permission方法对POST请求返回了False,需要检查该类的权限判断逻辑。 - 修复Model的save方法:当前Item的save方法存在两处错误:调用两次
super().save(),且self.suggested_value()是错误的调用方式(suggested_value是字段而非方法)。修复后的save方法如下:def save(self, *args, **kwargs): # 先处理默认值 if not self.retail_value: self.retail_value = self.suggested_value # 保存实例 super(Item, self).save(*args, **kwargs) # 分配权限 group = Group.objects.get(name=self.tenant) for perm in ['view_item', 'add_item','change_item']: assign_perm(perm, group, self) - 检查路由配置:确认使用
DefaultRouter正确注册ViewSet,没有自定义路由覆盖默认的POST路由。 - 确认Guardian权限注册:检查Django admin的权限列表,确保
add_item权限存在,且超级用户或其所属组拥有该权限。
内容的提问来源于stack exchange,提问作者momo668
相关产品推荐
相关产品推荐

