feat: added bypass_get_queryset decorator

This commit is contained in:
Laurent Riviere 2023-07-05 10:13:07 +00:00
parent 91ddfbd7f2
commit 42d1621e13
6 changed files with 29 additions and 7 deletions

View File

@ -155,6 +155,11 @@ If you are using ``DjangoObjectType`` you can define a custom `get_queryset`.
to Django documentation about ``prefetch_related``: https://docs.djangoproject.com/en/4.2/ref/models/querysets/#prefetch-related.
If you want to explicitly disable the execution of the custom ``get_queryset`` when resolving,
you can decorate the resolver with `@graphene_django.bypass_get_queryset`. Note that this
can lead to authorization leaks if you are performing authorization checks in the custom
``get_queryset``.
Filtering ID-based Node Access
------------------------------
@ -207,8 +212,8 @@ For Django 2.2 and above:
.. code:: python
urlpatterns = [
# some other urls
path('graphql/', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
# some other urls
path('graphql/', PrivateGraphQLView.as_view(graphiql=True, schema=schema)),
]
.. _LoginRequiredMixin: https://docs.djangoproject.com/en/dev/topics/auth/default/#the-loginrequired-mixin

View File

@ -57,9 +57,9 @@ specify the parameters in your settings.py:
.. code:: python
GRAPHENE = {
'SCHEMA': 'tutorial.quickstart.schema',
'SCHEMA_OUTPUT': 'data/schema.json', # defaults to schema.json,
'SCHEMA_INDENT': 2, # Defaults to None (displays all data on a single line)
'SCHEMA': 'tutorial.quickstart.schema',
'SCHEMA_OUTPUT': 'data/schema.json', # defaults to schema.json,
'SCHEMA_INDENT': 2, # Defaults to None (displays all data on a single line)
}

View File

@ -1,5 +1,6 @@
from .fields import DjangoConnectionField, DjangoListField
from .types import DjangoObjectType
from .utils import bypass_get_queryset
__version__ = "3.1.1"
@ -8,4 +9,5 @@ __all__ = [
"DjangoObjectType",
"DjangoListField",
"DjangoConnectionField",
"bypass_get_queryset",
]

View File

@ -278,11 +278,13 @@ def convert_onetoone_field_to_djangomodel(field, registry=None):
"""
resolver = super().wrap_resolve(parent_resolver)
# If `get_queryset` was not overridden in the DjangoObjectType,
# If `get_queryset` was not overridden in the DjangoObjectType
# or if we explicitly bypass the `get_queryset` method,
# we can just return the default resolver.
if (
_type.get_queryset.__func__
is DjangoObjectType.get_queryset.__func__
or getattr(resolver, "_bypass_get_queryset", False)
):
return resolver
@ -379,11 +381,13 @@ def convert_field_to_djangomodel(field, registry=None):
"""
resolver = super().wrap_resolve(parent_resolver)
# If `get_queryset` was not overridden in the DjangoObjectType,
# If `get_queryset` was not overridden in the DjangoObjectType
# or if we explicitly bypass the `get_queryset` method,
# we can just return the default resolver.
if (
_type.get_queryset.__func__
is DjangoObjectType.get_queryset.__func__
or getattr(resolver, "_bypass_get_queryset", False)
):
return resolver

View File

@ -6,6 +6,7 @@ from .utils import (
get_reverse_fields,
is_valid_django_model,
maybe_queryset,
bypass_get_queryset,
)
__all__ = [
@ -16,4 +17,5 @@ __all__ = [
"camelize",
"is_valid_django_model",
"GraphQLTestCase",
"bypass_get_queryset",
]

View File

@ -105,3 +105,12 @@ def set_rollback():
atomic_requests = connection.settings_dict.get("ATOMIC_REQUESTS", False)
if atomic_requests and connection.in_atomic_block:
transaction.set_rollback(True)
def bypass_get_queryset(resolver):
"""
Adds a bypass_get_queryset attribute to the resolver, which is used to
bypass any custom get_queryset method of the DjangoObjectType.
"""
resolver._bypass_get_queryset = True
return resolver