mirror of
				https://github.com/graphql-python/graphene.git
				synced 2025-11-04 18:07:48 +03:00 
			
		
		
		
	Filtering now available on nodes without defining fields
This commit is contained in:
		
							parent
							
								
									afd7aa8d72
								
							
						
					
					
						commit
						66189be4a9
					
				| 
						 | 
					@ -20,6 +20,7 @@ class DjangoConnectionField(ConnectionField):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ConnectionOrListField(Field):
 | 
					class ConnectionOrListField(Field):
 | 
				
			||||||
 | 
					    connection_field_class = ConnectionField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def internal_type(self, schema):
 | 
					    def internal_type(self, schema):
 | 
				
			||||||
        model_field = self.type
 | 
					        model_field = self.type
 | 
				
			||||||
| 
						 | 
					@ -27,7 +28,7 @@ class ConnectionOrListField(Field):
 | 
				
			||||||
        if not field_object_type:
 | 
					        if not field_object_type:
 | 
				
			||||||
            raise SkipField()
 | 
					            raise SkipField()
 | 
				
			||||||
        if is_node(field_object_type):
 | 
					        if is_node(field_object_type):
 | 
				
			||||||
            field = ConnectionField(field_object_type)
 | 
					            field = self.connection_field_class(field_object_type)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            field = Field(List(field_object_type))
 | 
					            field = Field(List(field_object_type))
 | 
				
			||||||
        field.contribute_to_class(self.object_type, self.attname)
 | 
					        field.contribute_to_class(self.object_type, self.attname)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
try:
 | 
					from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
 | 
				
			||||||
    import django_filters  # noqa
 | 
					
 | 
				
			||||||
except:
 | 
					if not DJANGO_FILTER_INSTALLED:
 | 
				
			||||||
    raise Exception(
 | 
					    raise Exception(
 | 
				
			||||||
        "Use of django filtering requires the django-filter package "
 | 
					        "Use of django filtering requires the django-filter package "
 | 
				
			||||||
        "be installed. You can do so using `pip install django-filter`"
 | 
					        "be installed. You can do so using `pip install django-filter`"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,12 @@
 | 
				
			||||||
 | 
					from .utils import DJANGO_FILTER_INSTALLED
 | 
				
			||||||
from ...core.classtypes.objecttype import ObjectTypeOptions
 | 
					from ...core.classtypes.objecttype import ObjectTypeOptions
 | 
				
			||||||
from ...relay.types import Node
 | 
					from ...relay.types import Node
 | 
				
			||||||
from ...relay.utils import is_node
 | 
					from ...relay.utils import is_node
 | 
				
			||||||
 | 
					
 | 
				
			||||||
VALID_ATTRS = ('model', 'only_fields', 'exclude_fields',
 | 
					VALID_ATTRS = ('model', 'only_fields', 'exclude_fields')
 | 
				
			||||||
               'filter_fields', 'filter_order_by')
 | 
					
 | 
				
			||||||
 | 
					if DJANGO_FILTER_INSTALLED:
 | 
				
			||||||
 | 
					    VALID_ATTRS += ('filter_fields', 'filter_order_by')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DjangoOptions(ObjectTypeOptions):
 | 
					class DjangoOptions(ObjectTypeOptions):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,23 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pytestmark = []
 | 
					from graphene import ObjectType, Schema
 | 
				
			||||||
 | 
					from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
 | 
				
			||||||
 | 
					from graphene.relay import NodeField
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    import django_filters
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    pytestmark.append(pytest.mark.skipif(True, reason='django_filters not installed'))
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    from graphene.contrib.django.filter import (GlobalIDFilter, DjangoFilterConnectionField,
 | 
					 | 
				
			||||||
                                                GlobalIDMultipleChoiceFilter)
 | 
					 | 
				
			||||||
    from graphene.contrib.django.tests.filter.filters import ArticleFilter, PetFilter
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from graphene.contrib.django import DjangoNode
 | 
					from graphene.contrib.django import DjangoNode
 | 
				
			||||||
from graphene.contrib.django.forms import GlobalIDFormField, GlobalIDMultipleChoiceField
 | 
					from graphene.contrib.django.forms import GlobalIDFormField, GlobalIDMultipleChoiceField
 | 
				
			||||||
from graphene.contrib.django.tests.models import Article, Pet, Reporter
 | 
					from graphene.contrib.django.tests.models import Article, Pet, Reporter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pytestmark = []
 | 
				
			||||||
 | 
					if DJANGO_FILTER_INSTALLED:
 | 
				
			||||||
 | 
					    import django_filters
 | 
				
			||||||
 | 
					    from graphene.contrib.django.filter import (GlobalIDFilter, DjangoFilterConnectionField,
 | 
				
			||||||
 | 
					                                                GlobalIDMultipleChoiceFilter)
 | 
				
			||||||
 | 
					    from graphene.contrib.django.tests.filter.filters import ArticleFilter, PetFilter
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    pytestmark.append(pytest.mark.skipif(True, reason='django_filters not installed'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pytestmark.append(pytest.mark.django_db)
 | 
					pytestmark.append(pytest.mark.django_db)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,6 +127,32 @@ def test_filter_filterset_information_on_meta():
 | 
				
			||||||
    assert_orderable(field)
 | 
					    assert_orderable(field)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test_filter_filterset_information_on_meta_related():
 | 
				
			||||||
 | 
					    class ReporterFilterNode(DjangoNode):
 | 
				
			||||||
 | 
					        class Meta:
 | 
				
			||||||
 | 
					            model = Reporter
 | 
				
			||||||
 | 
					            filter_fields = ['first_name', 'articles']
 | 
				
			||||||
 | 
					            filter_order_by = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class ArticleFilterNode(DjangoNode):
 | 
				
			||||||
 | 
					        class Meta:
 | 
				
			||||||
 | 
					            model = Article
 | 
				
			||||||
 | 
					            filter_fields = ['headline', 'reporter']
 | 
				
			||||||
 | 
					            filter_order_by = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class Query(ObjectType):
 | 
				
			||||||
 | 
					        all_reporters = DjangoFilterConnectionField(ReporterFilterNode)
 | 
				
			||||||
 | 
					        all_articles = DjangoFilterConnectionField(ArticleFilterNode)
 | 
				
			||||||
 | 
					        reporter = NodeField(ReporterFilterNode)
 | 
				
			||||||
 | 
					        article = NodeField(ArticleFilterNode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    schema = Schema(query=Query)
 | 
				
			||||||
 | 
					    schema.schema  # Trigger the schema loading
 | 
				
			||||||
 | 
					    articles_field = schema.get_type('ReporterFilterNode')._meta.fields_map['articles']
 | 
				
			||||||
 | 
					    assert_arguments(articles_field, 'headline', 'reporter')
 | 
				
			||||||
 | 
					    assert_orderable(articles_field)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def test_global_id_field_implicit():
 | 
					def test_global_id_field_implicit():
 | 
				
			||||||
    field = DjangoFilterConnectionField(ArticleNode, fields=['id'])
 | 
					    field = DjangoFilterConnectionField(ArticleNode, fields=['id'])
 | 
				
			||||||
    filterset_class = field.resolver_fn.get_filterset_class()
 | 
					    filterset_class = field.resolver_fn.get_filterset_class()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,13 @@
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from django.core.exceptions import ImproperlyConfigured
 | 
					from django.core.exceptions import ImproperlyConfigured
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					from graphene.contrib.django.utils import DJANGO_FILTER_INSTALLED
 | 
				
			||||||
    import django_filters  # noqa
 | 
					
 | 
				
			||||||
except ImportError:
 | 
					if DJANGO_FILTER_INSTALLED:
 | 
				
			||||||
    pytestmark = pytest.mark.skipif(True, reason='django_filters not installed')
 | 
					 | 
				
			||||||
else:
 | 
					 | 
				
			||||||
    from graphene.contrib.django.filter.resolvers import FilterConnectionResolver
 | 
					    from graphene.contrib.django.filter.resolvers import FilterConnectionResolver
 | 
				
			||||||
    from graphene.contrib.django.tests.filter.filters import ReporterFilter, ArticleFilter
 | 
					    from graphene.contrib.django.tests.filter.filters import ReporterFilter, ArticleFilter
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    pytestmark = pytest.mark.skipif(True, reason='django_filters not installed')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from graphene.contrib.django.tests.models import Reporter, Article
 | 
					from graphene.contrib.django.tests.models import Reporter, Article
 | 
				
			||||||
from graphene.contrib.django.tests.test_resolvers import ReporterNode, ArticleNode
 | 
					from graphene.contrib.django.tests.test_resolvers import ReporterNode, ArticleNode
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ from django.db import models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ...core.classtypes.objecttype import ObjectType, ObjectTypeMeta
 | 
					from ...core.classtypes.objecttype import ObjectType, ObjectTypeMeta
 | 
				
			||||||
from ...relay.types import Connection, Node, NodeMeta
 | 
					from ...relay.types import Connection, Node, NodeMeta
 | 
				
			||||||
 | 
					from .utils import DJANGO_FILTER_INSTALLED
 | 
				
			||||||
from .converter import convert_django_field
 | 
					from .converter import convert_django_field
 | 
				
			||||||
from .options import DjangoOptions
 | 
					from .options import DjangoOptions
 | 
				
			||||||
from .utils import get_reverse_fields, maybe_queryset
 | 
					from .utils import get_reverse_fields, maybe_queryset
 | 
				
			||||||
| 
						 | 
					@ -49,6 +50,15 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
 | 
				
			||||||
        return cls
 | 
					        return cls
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DjangoFilterObjectTypeMeta():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def convert_django_field(cls, field):
 | 
				
			||||||
 | 
					        from graphene.contrib.django.filter import DjangoFilterConnectionField
 | 
				
			||||||
 | 
					        field = super(DjangoFilterObjectTypeMeta, cls).convert_django_field(field)
 | 
				
			||||||
 | 
					        field.connection_field_class = DjangoFilterConnectionField
 | 
				
			||||||
 | 
					        return field
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class InstanceObjectType(ObjectType):
 | 
					class InstanceObjectType(ObjectType):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class Meta:
 | 
					    class Meta:
 | 
				
			||||||
| 
						 | 
					@ -92,7 +102,13 @@ class DjangoConnection(Connection):
 | 
				
			||||||
        return super(DjangoConnection, cls).from_list(iterable, *args, **kwargs)
 | 
					        return super(DjangoConnection, cls).from_list(iterable, *args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class DjangoNodeMeta(DjangoObjectTypeMeta, NodeMeta):
 | 
					django_node_meta_bases = (DjangoObjectTypeMeta, NodeMeta)
 | 
				
			||||||
 | 
					# Only include filter functionality if available
 | 
				
			||||||
 | 
					if DJANGO_FILTER_INSTALLED:
 | 
				
			||||||
 | 
					    django_node_meta_bases = (DjangoFilterObjectTypeMeta,) + django_node_meta_bases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DjangoNodeMeta(*django_node_meta_bases):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,12 @@ from graphene.utils import LazyList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from graphene import Argument, String
 | 
					from graphene import Argument, String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    import django_filters  # noqa
 | 
				
			||||||
 | 
					    DJANGO_FILTER_INSTALLED = True
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    DJANGO_FILTER_INSTALLED = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_type_for_model(schema, model):
 | 
					def get_type_for_model(schema, model):
 | 
				
			||||||
    schema = schema
 | 
					    schema = schema
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user