Django DRF、权限和测试:收到403个正在运行的测试,浏览器中200个OK

Django DRF、权限和测试:收到403个正在运行的测试,浏览器中200个OK,django,python-3.x,django-rest-framework,Django,Python 3.x,Django Rest Framework,随着我添加新视图和更多功能,我将继续我的Django Rest框架应用程序测试之旅。我必须承认,在这个阶段,我发现测试比实际编写和构建我的应用程序更难。我觉得关于测试DRF的资源远远少于关于使用DRF构建REST框架的资源。不过,这是人生,我坚持下去 我目前面临的问题是,在测试一个DRF视图集时收到403错误。我可以确认,当使用浏览器或常规python脚本访问端点时,视图及其权限工作正常 让我们从我的视图集中使用的模型开始 class QuizTracking(models.Model): ca

随着我添加新视图和更多功能,我将继续我的Django Rest框架应用程序测试之旅。我必须承认,在这个阶段,我发现测试比实际编写和构建我的应用程序更难。我觉得关于测试DRF的资源远远少于关于使用DRF构建REST框架的资源。不过,这是人生,我坚持下去

我目前面临的问题是,在测试一个DRF视图集时收到403错误。我可以确认,当使用浏览器或常规python脚本访问端点时,视图及其权限工作正常

让我们从我的视图集中使用的模型开始

class QuizTracking(models.Model):
case\u trunt=models.ForeignKey(casetrupt,on\u delete=models.CASCADE)
user=models.ForeignKey(CustomUser,on_delete=models.CASCADE)
答案=models.ForeignKey(答案,on_delete=models.CASCADE)
timestamp=models.DateTimeField(auto\u now\u add=True)
这里需要注意的是,用户有一个FK。这在确定权限时使用

这是我的测试函数。为了简洁起见,我没有为整个类包含代码

def测试问题检索(self):
"""
检查测验跟踪/ID是否返回200 OK,内容是否正确
"""
jim=用户(用户名='jimmy',密码='monkey123',电子邮件='jimmy@jim.com')
吉姆
测验跟踪=测验跟踪(答案=self.answer,案例尝试=self.case\u尝试,用户=jim)
测试跟踪。保存()
request=self.factory.get(f'/api/v1/progress/quick-tracking/{quick\u-tracking.id}'))
#如何使用permission.objects.get()引用自定义权限?
#permission=permission.objects.get()
#jim.user\u permissions.add(权限)
self.test_user.refresh_from_db()
强制验证(请求,用户=jim)
response=self.quick\u detail\u view(请求,pk=quick\u tracking.id)
打印(响应.数据)
打印(jim.id)
打印(测验跟踪.user.id)
self.assertContains(响应,“应答”)
self.assertEqual(response.status\u代码,status.HTTP\u 200\u OK)
在上面的代码中,我定义了一个用户,
jim
jim
拥有的
quick\u跟踪对象

我构建我的请求,
force_authenticate
请求和执行我的请求,并将响应存储在
response

这里要注意的有趣的事情是: -jim.id和quick_tracking.user.id的值相同 -我收到了403的回复

{'detail': ErrorDetail(string='You do not have permission to perform this action.', code='permission_denied')}
您可能已经注意到我已经注释掉了
permission=permission.objects.get()
我的理解是我需要传递这个我的权限类,在我的例子中是
IsUser
。但是,my DB中没有这方面的记录,因此
Permission.objects.get('IsUSer')
调用失败

因此,我的问题如下: -如何验证我的请求,以便收到200 OK? -我是否需要在测试中为我的用户添加权限,如果需要,使用哪种权限和语法

下面是我的视图,下面是我的自定义权限文件定义
IsUser

类QuickTrackingViewSet(ViewSet.ModelViewSet):
serializer_class=QuizTrackingSerializer
def get_queryset(自我):
返回QuizTracking.objects.all().filter(user=self.request.user)
def get_权限(自我):
如果self.action=='list':
self.permission\u classes=[IsUser,]
elif self.action==“检索”:
self.permission\u classes=[IsUser,]
返回超级(self.\uuuuuuuuuuuuuuuuuuuuuuuuu类,self).获取权限()
N.B.如果我注释掉
def get_permissions()
,那么我的测试就顺利通过了

我的自定义
权限.py

来自rest\u framework.permissions导入BasePermission
类颁发者(基本权限):
def具有_权限(自我、请求、查看):
return request.user和request.user.is\u superuser
类IsUser(基本权限):
def具有对象权限(自我、请求、查看、obj):
如果请求。用户:
如果request.user.is_超级用户:
返回真值
其他:
return obj==request.user
其他:
返回错误
干杯


C

问题似乎在于您的权限
IsUser

您可以将
QuizTracking
实例与用户实例进行比较

换行

return obj == request.user

一次性建议

您可以用以下更易于阅读的方式编写
IsUser

class IsUser(BasePermission):

    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated

    def has_object_permission(self, request, view, obj):
        return request.user.is_superuser or obj.user.id == request.user.id

请注意,只有在视图级别
has\u permission
返回True时才会调用
has\u object\u permission

@anowlinorbit无需担心。增加了一条“codereview”注释:-)
class IsUser(BasePermission):

    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated

    def has_object_permission(self, request, view, obj):
        return request.user.is_superuser or obj.user.id == request.user.id