Basic Proxy Model Support in Graphene-Django
Pull Request Link
Summary
This PR adds support for querying proxy models in Graphene-Django. Graphene-Django is a Python library that enables developers to create GraphQL services on top of the Django web framework.
Proxy models are an interesting feature of Django. In short, they let you modify the runtime behavior of a model while maintaining the same database table as the superclass. This is contrasted with the typical inheritance model in Django, which will create a separate table for each model.
Motivation
At Quorum, we use proxy models in many places. While experimenting with GraphQL, I ran into an issue where some of my queries were failing, and suspected there was an issue with types. It turned out that our proxy models defined their own __init__
methods which set their class to be the proxy model class at runtime. Graphene did not yet handle this situation.
Details and Example
Previously, while you were still able to query for all objects of a particular type, of which some may be proxy models, an error would be thrown if at runtime the Python class were changed. In graphene_django_types.py
there is a line that verifies that each node in the resulting GraphQL matches the type of the declared type in the schema. I'll use a test case from my PR to illustrate this.
Let's say you have a Reporter
Django model like so:
class Reporter(models.Model):
first_name = ...
last_name
...
Your GraphQL schema might look like:
class ReporterType(DjangoObjectType):
class Meta:
model = Reporter # this is your Django model
interfaces = (Node, )
use_connection = True
then, you might want to query for all Reporters:
class Query(graphene.ObjectType):
all_reporters = DjangoConnectionFilterField(ReporterType)
The line model == cls._meta.model
(here) would make sure that the model of each reporter type matches the declared model in the ReporterType
meta
. If you had just reporters, this would be totally fine.
Let's say you also had another Django model called CNNReporter
that is a proxy model to of Reporter
:
class CNNReporter(Reporter):
class Meta:
proxy = True
Now, if we override the __init__
method of the Reporter
class to modify its class (link to code), our proxy model instances will have a different type at runtime than instances of Reporter. The line would compare Reporter == CNNReporter, which would fail.
If we instead check the concrete_model
field in the _meta
of the instance’s model, we will always get the same type for all objects in the query, regardless of proxy model inheritance. In this case, CNNReporter's
concrete_model
is Reporter
. The change is here.
Posted on Utopian.io - Rewarding Open Source Contributors
Hey @jmares I am @utopian-io. I have just upvoted you!
Achievements
Community-Driven Witness!
I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!
Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x
Thank you for the contribution. It has been approved.
You can contact us on Discord.
[utopian-moderator]