Skip to content

"R" raises an exception when following through a one-to-many relation #22

@philipstarkey

Description

@philipstarkey

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions