mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-11-04 09:57:53 +03:00 
			
		
		
		
	Merge pull request #603 from abettke/fix/enhanced-proxy-model-support
Adds enhanced support for proxy models.
This commit is contained in:
		
						commit
						b271b259bd
					
				| 
						 | 
				
			
			@ -65,6 +65,11 @@ class Reporter(models.Model):
 | 
			
		|||
            self.__class__ = CNNReporter
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CNNReporterManager(models.Manager):
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        return super(CNNReporterManager, self).get_queryset().filter(reporter_type=2)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CNNReporter(Reporter):
 | 
			
		||||
    """
 | 
			
		||||
    This class is a proxy model for Reporter, used for testing
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +79,8 @@ class CNNReporter(Reporter):
 | 
			
		|||
    class Meta:
 | 
			
		||||
        proxy = True
 | 
			
		||||
 | 
			
		||||
    objects = CNNReporterManager()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Article(models.Model):
 | 
			
		||||
    headline = models.CharField(max_length=100)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,3 +1,4 @@
 | 
			
		|||
import base64
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
| 
						 | 
				
			
			@ -7,6 +8,7 @@ from py.test import raises
 | 
			
		|||
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
 | 
			
		||||
from graphql_relay import to_global_id
 | 
			
		||||
import graphene
 | 
			
		||||
from graphene.relay import Node
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -951,8 +953,7 @@ def test_should_handle_inherited_choices():
 | 
			
		|||
 | 
			
		||||
def test_proxy_model_support():
 | 
			
		||||
    """
 | 
			
		||||
    This test asserts that we can query for all Reporters,
 | 
			
		||||
    even if some are of a proxy model type at runtime.
 | 
			
		||||
    This test asserts that we can query for all Reporters and proxied Reporters.
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    class ReporterType(DjangoObjectType):
 | 
			
		||||
| 
						 | 
				
			
			@ -961,11 +962,17 @@ def test_proxy_model_support():
 | 
			
		|||
            interfaces = (Node,)
 | 
			
		||||
            use_connection = True
 | 
			
		||||
 | 
			
		||||
    reporter_1 = Reporter.objects.create(
 | 
			
		||||
    class CNNReporterType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = CNNReporter
 | 
			
		||||
            interfaces = (Node,)
 | 
			
		||||
            use_connection = True
 | 
			
		||||
 | 
			
		||||
    reporter = Reporter.objects.create(
 | 
			
		||||
        first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    reporter_2 = CNNReporter.objects.create(
 | 
			
		||||
    cnn_reporter = CNNReporter.objects.create(
 | 
			
		||||
        first_name="Some",
 | 
			
		||||
        last_name="Guy",
 | 
			
		||||
        email="someguy@cnn.com",
 | 
			
		||||
| 
						 | 
				
			
			@ -975,6 +982,7 @@ def test_proxy_model_support():
 | 
			
		|||
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        all_reporters = DjangoConnectionField(ReporterType)
 | 
			
		||||
        cnn_reporters = DjangoConnectionField(CNNReporterType)
 | 
			
		||||
 | 
			
		||||
    schema = graphene.Schema(query=Query)
 | 
			
		||||
    query = """
 | 
			
		||||
| 
						 | 
				
			
			@ -986,14 +994,26 @@ def test_proxy_model_support():
 | 
			
		|||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            cnnReporters {
 | 
			
		||||
                edges {
 | 
			
		||||
                    node {
 | 
			
		||||
                        id
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    expected = {
 | 
			
		||||
        "allReporters": {
 | 
			
		||||
            "edges": [
 | 
			
		||||
                {"node": {"id": "UmVwb3J0ZXJUeXBlOjE="}},
 | 
			
		||||
                {"node": {"id": "UmVwb3J0ZXJUeXBlOjI="}},
 | 
			
		||||
                {"node": {"id": to_global_id("ReporterType", reporter.id)}},
 | 
			
		||||
                {"node": {"id": to_global_id("ReporterType", cnn_reporter.id)}},
 | 
			
		||||
            ]
 | 
			
		||||
        },
 | 
			
		||||
        "cnnReporters": {
 | 
			
		||||
            "edges": [
 | 
			
		||||
                {"node": {"id": to_global_id("CNNReporterType", cnn_reporter.id)}}
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1001,69 +1021,7 @@ def test_proxy_model_support():
 | 
			
		|||
    result = schema.execute(query)
 | 
			
		||||
    assert not result.errors
 | 
			
		||||
    assert result.data == expected
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def test_proxy_model_fails():
 | 
			
		||||
    """
 | 
			
		||||
    This test asserts that if you try to query for a proxy model,
 | 
			
		||||
    that query will fail with:
 | 
			
		||||
        GraphQLError('Expected value of type "CNNReporterType" but got:
 | 
			
		||||
            CNNReporter.',)
 | 
			
		||||
 | 
			
		||||
    This is because a proxy model has the identical model definition
 | 
			
		||||
    to its superclass, and defines its behavior at runtime, rather than
 | 
			
		||||
    at the database level. Currently, filtering objects of the proxy models'
 | 
			
		||||
    type isn't supported. It would require a field on the model that would
 | 
			
		||||
    represent the type, and it doesn't seem like there is a clear way to
 | 
			
		||||
    enforce this pattern across all projects
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    class CNNReporterType(DjangoObjectType):
 | 
			
		||||
        class Meta:
 | 
			
		||||
            model = CNNReporter
 | 
			
		||||
            interfaces = (Node,)
 | 
			
		||||
            use_connection = True
 | 
			
		||||
 | 
			
		||||
    reporter_1 = Reporter.objects.create(
 | 
			
		||||
        first_name="John", last_name="Doe", email="johndoe@example.com", a_choice=1
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    reporter_2 = 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
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Query(graphene.ObjectType):
 | 
			
		||||
        all_reporters = DjangoConnectionField(CNNReporterType)
 | 
			
		||||
 | 
			
		||||
    schema = graphene.Schema(query=Query)
 | 
			
		||||
    query = """
 | 
			
		||||
        query ProxyModelQuery {
 | 
			
		||||
            allReporters {
 | 
			
		||||
                edges {
 | 
			
		||||
                    node {
 | 
			
		||||
                        id
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    """
 | 
			
		||||
 | 
			
		||||
    expected = {
 | 
			
		||||
        "allReporters": {
 | 
			
		||||
            "edges": [
 | 
			
		||||
                {"node": {"id": "UmVwb3J0ZXJUeXBlOjE="}},
 | 
			
		||||
                {"node": {"id": "UmVwb3J0ZXJUeXBlOjI="}},
 | 
			
		||||
            ]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result = schema.execute(query)
 | 
			
		||||
    assert result.errors
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
def test_should_resolve_get_queryset_connectionfields():
 | 
			
		||||
    reporter_1 = Reporter.objects.create(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -131,7 +131,11 @@ class DjangoObjectType(ObjectType):
 | 
			
		|||
        if not is_valid_django_model(type(root)):
 | 
			
		||||
            raise Exception(('Received incompatible instance "{}".').format(root))
 | 
			
		||||
 | 
			
		||||
        model = root._meta.model._meta.concrete_model
 | 
			
		||||
        if cls._meta.model._meta.proxy:
 | 
			
		||||
            model = root._meta.model
 | 
			
		||||
        else:
 | 
			
		||||
            model = root._meta.model._meta.concrete_model
 | 
			
		||||
 | 
			
		||||
        return model == cls._meta.model
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue
	
	Block a user