Basic Proxy Model Support in Graphene-Django

View this thread on: d.buzz | hive.blog | peakd.com | ecency.com
·@jmares·
0.000 HBD
Basic Proxy Model Support in Graphene-Django
# [Pull Request Link](https://github.com/graphql-python/graphene-django/pull/373)

# Summary 
This PR adds support for querying proxy models in [Graphene-Django](http://docs.graphene-python.org/projects/django/en/latest/). 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)](https://github.com/graphql-python/graphene-django/pull/373/files#diff-6926ea790e42fa924302b75462dfef72L111) 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)](https://github.com/graphql-python/graphene-django/pull/373/files#diff-b60c4013deb0c92607a948d32a694fb8R43), 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](https://github.com/graphql-python/graphene-django/pull/373/files#diff-6926ea790e42fa924302b75462dfef72R112). 

<br /><hr/><em>Posted on <a href="https://utopian.io/utopian-io/@jmares/basic-proxy-model-support-in-graphene-django">Utopian.io -  Rewarding Open Source Contributors</a></em><hr/>
👍 , , , , , , , , , , , ,