Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow annotating models with the result of a permission query #43

Open
peacememories opened this issue Jan 23, 2024 · 1 comment
Open

Comments

@peacememories
Copy link

Hi, and thanks for your hard work. We've recently started using Bridgekeeper in our application because it seems to provide a lot of flexibility when it comes to defining rules. One stumbling block we've hit, though, is when we do not want to filter using a rule, but instead want to annotate a queryset with the result of the rule.

This is useful for us, e.g. when inaccessible objects in a list should not be omitted but instead marked as such.

We initially tried using the query field of the permission, since django allows annotating using a Q object, but this seems to not work, as the code

q = perms["application.has_permission"].query(user)
if q == UNIVERSAL:
    q = models.Value(True)
if q == EMPTY:
    q = models.Value(False)
print("====================================")
print(q)
return self.annotate(
    is_blocked=models.functions.Cast(q, models.BooleanField())
)

always evaluates to True.

A workaround is to perform the filtering query and then annotate by using in, but this seems needlessly expensive.

It would be great if Bridgekeeper could expose some way to get at an F object for use in annotations.

@philipstarkey
Copy link

philipstarkey commented Jan 23, 2024

@peacememories I've done something similar before - you should be able to get it to work by using Case and When (see https://docs.djangoproject.com/en/5.0/ref/models/conditional-expressions/ ). E.g. self.annotate(is_blocked=Case(When(q, then=Value(True)), default=Value(False))).

In some cases I've seen this trigger duplicate rows in the queryset (as you can't make the Case/When distinct) in which case I've used Count(filter=q, distinct=True, ...) as a work around.

There may be more optimal ways of doing it for your particular query, but that should point you in the right direction!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants