Skip to content

Fix filtering with GlobalIDFilter #977

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

Merged
merged 1 commit into from
Jun 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion graphene_django/filter/fields.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from collections import OrderedDict
from functools import partial

from django.core.exceptions import ValidationError
from graphene.types.argument import to_arguments
from ..fields import DjangoConnectionField
from .utils import get_filtering_args_from_filterset, get_filterset_class
Expand Down Expand Up @@ -59,7 +60,12 @@ def resolve_queryset(
connection, iterable, info, args
)
filter_kwargs = {k: v for k, v in args.items() if k in filtering_args}
return filterset_class(data=filter_kwargs, queryset=qs, request=info.context).qs
filterset = filterset_class(
data=filter_kwargs, queryset=qs, request=info.context
)
if filterset.form.is_valid():
return filterset.qs
raise ValidationError(filterset.form.errors.as_json())
Comment on lines +66 to +68
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To support Python 2.7 and django-filter 1.1 that form property is needed. In Graphene-Django v3 we use django-filter 2.x which allows to call is_valid and errors directly on filterset instances. We may want to refactor that for v3 as it slightly improves readability.


def get_queryset_resolver(self):
return partial(
Expand Down
108 changes: 108 additions & 0 deletions graphene_django/filter/tests/test_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,114 @@ def test_global_id_field_relation():
assert id_filter.field_class == GlobalIDFormField


def test_global_id_field_relation_with_filter():
class ReporterFilterNode(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)
filter_fields = ["first_name", "articles"]

class ArticleFilterNode(DjangoObjectType):
class Meta:
model = Article
interfaces = (Node,)
filter_fields = ["headline", "reporter"]

class Query(ObjectType):
all_reporters = DjangoFilterConnectionField(ReporterFilterNode)
all_articles = DjangoFilterConnectionField(ArticleFilterNode)
reporter = Field(ReporterFilterNode)
article = Field(ArticleFilterNode)

r1 = Reporter.objects.create(first_name="r1", last_name="r1", email="r1@test.com")
r2 = Reporter.objects.create(first_name="r2", last_name="r2", email="r2@test.com")
Article.objects.create(
headline="a1",
pub_date=datetime.now(),
pub_date_time=datetime.now(),
reporter=r1,
editor=r1,
)
Article.objects.create(
headline="a2",
pub_date=datetime.now(),
pub_date_time=datetime.now(),
reporter=r2,
editor=r2,
)

# Query articles created by the reporter `r1`
query = """
query {
allArticles (reporter: "UmVwb3J0ZXJGaWx0ZXJOb2RlOjE=") {
edges {
node {
id
}
}
}
}
"""
schema = Schema(query=Query)
result = schema.execute(query)
assert not result.errors
# We should only get back a single article
assert len(result.data["allArticles"]["edges"]) == 1


def test_global_id_field_relation_with_filter_not_valid_id():
class ReporterFilterNode(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node,)
filter_fields = ["first_name", "articles"]

class ArticleFilterNode(DjangoObjectType):
class Meta:
model = Article
interfaces = (Node,)
filter_fields = ["headline", "reporter"]

class Query(ObjectType):
all_reporters = DjangoFilterConnectionField(ReporterFilterNode)
all_articles = DjangoFilterConnectionField(ArticleFilterNode)
reporter = Field(ReporterFilterNode)
article = Field(ArticleFilterNode)

r1 = Reporter.objects.create(first_name="r1", last_name="r1", email="r1@test.com")
r2 = Reporter.objects.create(first_name="r2", last_name="r2", email="r2@test.com")
Article.objects.create(
headline="a1",
pub_date=datetime.now(),
pub_date_time=datetime.now(),
reporter=r1,
editor=r1,
)
Article.objects.create(
headline="a2",
pub_date=datetime.now(),
pub_date_time=datetime.now(),
reporter=r2,
editor=r2,
)

# Filter by the global ID that does not exist
query = """
query {
allArticles (reporter: "fake_global_id") {
edges {
node {
id
}
}
}
}
"""
schema = Schema(query=Query)
result = schema.execute(query)
assert "Invalid ID specified." in result.errors[0].message


def test_global_id_multiple_field_implicit():
field = DjangoFilterConnectionField(ReporterNode, fields=["pets"])
filterset_class = field.filterset_class
Expand Down