mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-11-04 01:47:57 +03:00 
			
		
		
		
	Adds enhanced support for proxy models.
This commit is contained in:
		
							parent
							
								
									ea2cd9894f
								
							
						
					
					
						commit
						36ac5626e9
					
				| 
						 | 
					@ -65,6 +65,11 @@ class Reporter(models.Model):
 | 
				
			||||||
            self.__class__ = CNNReporter
 | 
					            self.__class__ = CNNReporter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CNNReporterManager(models.Manager):
 | 
				
			||||||
 | 
					    def get_queryset(self):
 | 
				
			||||||
 | 
					        return super(CNNReporterManager, self).get_queryset().filter(reporter_type=2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CNNReporter(Reporter):
 | 
					class CNNReporter(Reporter):
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    This class is a proxy model for Reporter, used for testing
 | 
					    This class is a proxy model for Reporter, used for testing
 | 
				
			||||||
| 
						 | 
					@ -74,6 +79,8 @@ class CNNReporter(Reporter):
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
        proxy = True
 | 
					        proxy = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    objects = CNNReporterManager()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Article(models.Model):
 | 
					class Article(models.Model):
 | 
				
			||||||
    headline = models.CharField(max_length=100)
 | 
					    headline = models.CharField(max_length=100)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,4 @@
 | 
				
			||||||
 | 
					import base64
 | 
				
			||||||
import datetime
 | 
					import datetime
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
| 
						 | 
					@ -895,8 +896,7 @@ def test_should_handle_inherited_choices():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_proxy_model_support():
 | 
					def test_proxy_model_support():
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    This test asserts that we can query for all Reporters,
 | 
					    This test asserts that we can query for all Reporters and proxied Reporters.
 | 
				
			||||||
    even if some are of a proxy model type at runtime.
 | 
					 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class ReporterType(DjangoObjectType):
 | 
					    class ReporterType(DjangoObjectType):
 | 
				
			||||||
| 
						 | 
					@ -905,11 +905,17 @@ def test_proxy_model_support():
 | 
				
			||||||
            interfaces = (Node,)
 | 
					            interfaces = (Node,)
 | 
				
			||||||
            use_connection = True
 | 
					            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
 | 
					        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",
 | 
					        first_name="Some",
 | 
				
			||||||
        last_name="Guy",
 | 
					        last_name="Guy",
 | 
				
			||||||
        email="someguy@cnn.com",
 | 
					        email="someguy@cnn.com",
 | 
				
			||||||
| 
						 | 
					@ -919,6 +925,7 @@ def test_proxy_model_support():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Query(graphene.ObjectType):
 | 
					    class Query(graphene.ObjectType):
 | 
				
			||||||
        all_reporters = DjangoConnectionField(ReporterType)
 | 
					        all_reporters = DjangoConnectionField(ReporterType)
 | 
				
			||||||
 | 
					        cnn_reporters = DjangoConnectionField(CNNReporterType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    schema = graphene.Schema(query=Query)
 | 
					    schema = graphene.Schema(query=Query)
 | 
				
			||||||
    query = """
 | 
					    query = """
 | 
				
			||||||
| 
						 | 
					@ -930,14 +937,26 @@ def test_proxy_model_support():
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            cnnReporters {
 | 
				
			||||||
 | 
					                edges {
 | 
				
			||||||
 | 
					                    node {
 | 
				
			||||||
 | 
					                        id
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    expected = {
 | 
					    expected = {
 | 
				
			||||||
        "allReporters": {
 | 
					        "allReporters": {
 | 
				
			||||||
            "edges": [
 | 
					            "edges": [
 | 
				
			||||||
                {"node": {"id": "UmVwb3J0ZXJUeXBlOjE="}},
 | 
					                {"node": {"id": base64.b64encode("ReporterType:{}".format(reporter.id))}},
 | 
				
			||||||
                {"node": {"id": "UmVwb3J0ZXJUeXBlOjI="}},
 | 
					                {"node": {"id": base64.b64encode("ReporterType:{}".format(cnn_reporter.id))}},
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "cnnReporters": {
 | 
				
			||||||
 | 
					            "edges": [
 | 
				
			||||||
 | 
					                {"node": {"id": base64.b64encode("CNNReporterType:{}".format(cnn_reporter.id))}}
 | 
				
			||||||
            ]
 | 
					            ]
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -945,65 +964,3 @@ def test_proxy_model_support():
 | 
				
			||||||
    result = schema.execute(query)
 | 
					    result = schema.execute(query)
 | 
				
			||||||
    assert not result.errors
 | 
					    assert not result.errors
 | 
				
			||||||
    assert result.data == expected
 | 
					    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
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -130,7 +130,11 @@ class DjangoObjectType(ObjectType):
 | 
				
			||||||
        if not is_valid_django_model(type(root)):
 | 
					        if not is_valid_django_model(type(root)):
 | 
				
			||||||
            raise Exception(('Received incompatible instance "{}".').format(root))
 | 
					            raise Exception(('Received incompatible instance "{}".').format(root))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if cls._meta.model._meta.proxy:
 | 
				
			||||||
 | 
					            model = root._meta.model
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
            model = root._meta.model._meta.concrete_model
 | 
					            model = root._meta.model._meta.concrete_model
 | 
				
			||||||
 | 
					            
 | 
				
			||||||
        return model == cls._meta.model
 | 
					        return model == cls._meta.model
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user