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

Multi-/Cross-fields-permission-check for DjangoObjectType #997

Open
Eraldo opened this issue Jun 29, 2020 · 0 comments
Open

Multi-/Cross-fields-permission-check for DjangoObjectType #997

Eraldo opened this issue Jun 29, 2020 · 0 comments

Comments

@Eraldo
Copy link

Eraldo commented Jun 29, 2020

The Challenge

I have models where I want to restrict the content of some fields based on the relationship between the user and the current instance of that model.

The challenge is that if I write custom field resolvers for each field that I want to alter, I end up doing a db query for each such field, which ends up becoming really slow if I get a whole QuerySet of the node type.

How can I prevent doing a query for each and every field resolution?

Example

If I have a model Book and each book has an author field which is a FK to the user model.
Then on the BookNode I have the field-level checks:

  def resolve_authors_only_field1(self, info):
        user = info.context.user
        if user in self.author_set.all():
            return self.authors_only_field1
        return "some default"  # In case of a required field type

  def resolve_authors_only_field2(self, info):
        user = info.context.user
        if user in self.author_set.all():
            return self.authors_only_field2
        return None  # In case of an optional field type

Performance Bottleneck

This does work, but as far as I understand it will do a db query for executing every field resolver!
Meaning: If I get 20 books and I have 20 restricted/conditional fields, I end up doing 400 db queries. 😐

Solution Ideas

Mental Inspiration

FYI: As an inspiration I was also looking at similar multi-/cross-field challenges.
I also looked at how Django Form validation tries to allow something similar.

Single field validation:

def validate_myfield(self, value):
    ...

Cross-field validation:

def validate(self, data):
    ...

Solution idea 1: Cross-field resolver hook

Being able to change the fields based on a hook after individual fields have been resolved:

Single field resolver hook:

def resolve_myfield(self, info):
    ...

Cross-field resolver hook:

def resolve_fields(self, info, data):
    ...

Solution idea 2: Dynamic fields/only-fields/exclude-fields

Make it possible to change the fields/only-fields/exclude-fields attributes at runtime. (e.g. when starting to resolve the node?)
Or allow fields/only-fields/exclude-fields to accept a function that will be called when resolving the node.

Update: @jkimbo pointed out that it’s not a good idea to change the types at runtime and that the schema should be static.

Alternative Ideas

Changing the type dynamically when resolving: #79 (comment)
(Nice idea, but might end up adding more complexity and types than necessary.)

Overwriting the resolver entirely: #79 (comment)

Additional context

graphene 2.1.8
graphene-django 2.11.0

If there are any questions to better explain my scenario/user-cases/etc.
Please feel free to ask and I will do my best to explain. :)

Comments

I really wonder if there is a smarter / more intuitive way of rewriting my code to not do a query per field. 🤔

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

No branches or pull requests

1 participant