-
Notifications
You must be signed in to change notification settings - Fork 14
Description
I have the following model structure (approximately):
USER = get_user_model()
class Company(models.Model):
#fields omitted for brevity
class Staff(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
user = models.ForeignKey(USER, on_delete=models.CASCADE)
and a permission perms["core.view_company"] = R(staff__user=lambda user: user)
I'm creating API endpoints using Django REST Framework, integrated with bridgekeeper as per the documentation. DRF view is a bog-standard ModelViewSet
, DRF serializer is a bog-standard HyperlinkedModelSerializer
.
Django version: 3.0.3
bridgekeeper version: 0.9
When accessing the API endpoint for a specific company (e.g. /api/company/1/
) I get the following exception from bridgekeeper:
Traceback (most recent call last):
File "C:\Anaconda3\lib\site-packages\rest_framework\views.py", line 343, in check_object_permissions
if not permission.has_object_permission(request, self, obj):
File "C:\Anaconda3\lib\site-packages\bridgekeeper\rest_framework.py", line 166, in has_object_permission
return self.get_permission(request, view, obj).check(request.user, obj)
File "C:\Anaconda3\lib\site-packages\bridgekeeper\rules.py", line 203, in check
return self.left.check(user, instance) or self.right.check(user, instance)
File "C:\Anaconda3\lib\site-packages\bridgekeeper\rules.py", line 322, in check
field = lhs.__class__._meta.get_field(
Exception Type: AttributeError at /api/company/1/
Exception Value: type object 'RelatedManager' has no attribute '_meta'
Note that this exception is not raised when accessing /api/company/
(the correct list of companies is returned)
It seems that the R
syntax in bridgekeeper can't handle following relationships backwards through a many-to-one relationship (although I think it might work if the many-to-one is at the end of the chain?).
Unless I'm doing something wrong, I think this is inconsistent with the Q
and filter
syntax in Django. For example, Company.objects.all().filter(staff__user=user)
returns the expected set of companies. So I'm logging it as a bug!
In the meantime, I'm achieving the same thing with In(lambda user: set([staff.company for staff in user.staff_set.all()]))
but I'm guessing this is less efficient.