mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-05 12:53:12 +03:00
support reverse relationship for proxy models
This commit is contained in:
parent
daa0ab046b
commit
b08f2d6faf
|
@ -1067,6 +1067,110 @@ def test_proxy_model_support():
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_proxy_model_support_reverse_relationships():
|
||||||
|
"""
|
||||||
|
This test asserts that we can query reverse relationships for all Reporters and proxied Reporters.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class FilmType(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = Film
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
class ReporterType(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = Reporter
|
||||||
|
interfaces = (Node,)
|
||||||
|
use_connection = True
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
class CNNReporterType(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = CNNReporter
|
||||||
|
interfaces = (Node,)
|
||||||
|
use_connection = True
|
||||||
|
fields = "__all__"
|
||||||
|
|
||||||
|
film = Film.objects.create(genre="do")
|
||||||
|
|
||||||
|
reporter = Reporter.objects.create(
|
||||||
|
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
|
||||||
|
)
|
||||||
|
|
||||||
|
cnn_reporter = CNNReporter.objects.create(
|
||||||
|
first_name="Some",
|
||||||
|
last_name="Guy",
|
||||||
|
email="someguy@cnn.com",
|
||||||
|
a_choice=1,
|
||||||
|
reporter_type=2, # set this guy to be CNN
|
||||||
|
)
|
||||||
|
|
||||||
|
film.reporters.add(cnn_reporter)
|
||||||
|
film.save()
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
all_reporters = DjangoConnectionField(ReporterType)
|
||||||
|
cnn_reporters = DjangoConnectionField(CNNReporterType)
|
||||||
|
|
||||||
|
schema = graphene.Schema(query=Query)
|
||||||
|
query = """
|
||||||
|
query ProxyModelQuery {
|
||||||
|
allReporters {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
films {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cnnReporters {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
films {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
"allReporters": {
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": to_global_id("ReporterType", reporter.id),
|
||||||
|
"films": [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": to_global_id("ReporterType", cnn_reporter.id),
|
||||||
|
"films": [{"id": f"{film.id}"}],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"cnnReporters": {
|
||||||
|
"edges": [
|
||||||
|
{
|
||||||
|
"node": {
|
||||||
|
"id": to_global_id("CNNReporterType", cnn_reporter.id),
|
||||||
|
"films": [{"id": f"{film.id}"}],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result = schema.execute(query)
|
||||||
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
def test_should_resolve_get_queryset_connectionfields():
|
def test_should_resolve_get_queryset_connectionfields():
|
||||||
reporter_1 = Reporter.objects.create(
|
reporter_1 = Reporter.objects.create(
|
||||||
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
|
first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
|
||||||
|
|
|
@ -4,8 +4,8 @@ import pytest
|
||||||
from django.utils.translation import gettext_lazy
|
from django.utils.translation import gettext_lazy
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from ..utils import camelize, get_model_fields, GraphQLTestCase
|
from ..utils import camelize, get_model_fields, get_reverse_fields, GraphQLTestCase
|
||||||
from .models import Film, Reporter
|
from .models import Film, Reporter, CNNReporter
|
||||||
from ..utils.testing import graphql_query
|
from ..utils.testing import graphql_query
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,6 +19,13 @@ def test_get_model_fields_no_duplication():
|
||||||
assert len(film_fields) == len(film_name_set)
|
assert len(film_fields) == len(film_name_set)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_reverse_fields_includes_proxied_models():
|
||||||
|
reporter_fields = get_reverse_fields(Reporter, [])
|
||||||
|
cnn_reporter_fields = get_reverse_fields(CNNReporter, [])
|
||||||
|
|
||||||
|
assert len(list(reporter_fields)) == len(list(cnn_reporter_fields))
|
||||||
|
|
||||||
|
|
||||||
def test_camelize():
|
def test_camelize():
|
||||||
assert camelize({}) == {}
|
assert camelize({}) == {}
|
||||||
assert camelize("value_a") == "value_a"
|
assert camelize("value_a") == "value_a"
|
||||||
|
|
|
@ -38,17 +38,23 @@ def camelize(data):
|
||||||
|
|
||||||
|
|
||||||
def get_reverse_fields(model, local_field_names):
|
def get_reverse_fields(model, local_field_names):
|
||||||
for name, attr in model.__dict__.items():
|
model_ancestry = [model]
|
||||||
# Don't duplicate any local fields
|
# Include proxy models when getting related fields
|
||||||
if name in local_field_names:
|
if model._meta.proxy:
|
||||||
continue
|
model_ancestry.append(model._meta.proxy_for_model)
|
||||||
|
|
||||||
# "rel" for FK and M2M relations and "related" for O2O Relations
|
for _model in model_ancestry:
|
||||||
related = getattr(attr, "rel", None) or getattr(attr, "related", None)
|
for name, attr in _model.__dict__.items():
|
||||||
if isinstance(related, models.ManyToOneRel):
|
# Don't duplicate any local fields
|
||||||
yield (name, related)
|
if name in local_field_names:
|
||||||
elif isinstance(related, models.ManyToManyRel) and not related.symmetrical:
|
continue
|
||||||
yield (name, related)
|
|
||||||
|
# "rel" for FK and M2M relations and "related" for O2O Relations
|
||||||
|
related = getattr(attr, "rel", None) or getattr(attr, "related", None)
|
||||||
|
if isinstance(related, models.ManyToOneRel):
|
||||||
|
yield (name, related)
|
||||||
|
elif isinstance(related, models.ManyToManyRel) and not related.symmetrical:
|
||||||
|
yield (name, related)
|
||||||
|
|
||||||
|
|
||||||
def maybe_queryset(value):
|
def maybe_queryset(value):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user