You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
The text was updated successfully, but these errors were encountered:
This Fixesdaisylb#22
`R` rules that traverse many-to-one or many-to-many relationships are now broken up automatically within `R.check()` into multiple, chained `R` rules.
Tests to confirm both the original nested R syntax, and a the new unnested syntax, have been added.
So I realised today that I had missed a line in the documentation here that says:
If the argument refers to a foreign key or many-to-many relationship, another Rule object.
That made me realise that I should really have been doing perms["core.view_company"] = R(staff=R(user=lambda user: user)) which worked as I expected.
That in turn made me realise that this conversion could actually be automated inside R.check! So I've made PR #23 which does that conversion and added some tests to cover the case. I hope it's a useful contribution!
I have the following model structure (approximately):
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-standardHyperlinkedModelSerializer
.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: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
andfilter
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.The text was updated successfully, but these errors were encountered: