mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-07-13 17:52:19 +03:00
Merge aa55a86f0d
into 2600f0f041
This commit is contained in:
commit
71a8c1924a
|
@ -61,7 +61,7 @@ class DjangoFilterConnectionField(DjangoConnectionField):
|
||||||
low = default_queryset.query.low_mark or queryset.query.low_mark
|
low = default_queryset.query.low_mark or queryset.query.low_mark
|
||||||
high = default_queryset.query.high_mark or queryset.query.high_mark
|
high = default_queryset.query.high_mark or queryset.query.high_mark
|
||||||
default_queryset.query.clear_limits()
|
default_queryset.query.clear_limits()
|
||||||
queryset = default_queryset & queryset
|
queryset = queryset & default_queryset
|
||||||
queryset.query.set_limits(low, high)
|
queryset.query.set_limits(low, high)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from datetime import datetime
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from graphene import Field, ObjectType, Schema, Argument, Float
|
from graphene import Field, ObjectType, Schema, Argument, Float, Boolean, String
|
||||||
from graphene.relay import Node
|
from graphene.relay import Node
|
||||||
from graphene_django import DjangoObjectType
|
from graphene_django import DjangoObjectType
|
||||||
from graphene_django.forms import (GlobalIDFormField,
|
from graphene_django.forms import (GlobalIDFormField,
|
||||||
|
@ -10,6 +10,10 @@ from graphene_django.forms import (GlobalIDFormField,
|
||||||
from graphene_django.tests.models import Article, Pet, Reporter
|
from graphene_django.tests.models import Article, Pet, Reporter
|
||||||
from graphene_django.utils import DJANGO_FILTER_INSTALLED
|
from graphene_django.utils import DJANGO_FILTER_INSTALLED
|
||||||
|
|
||||||
|
# for annotation test
|
||||||
|
from django.db.models import TextField, Value
|
||||||
|
from django.db.models.functions import Concat
|
||||||
|
|
||||||
pytestmark = []
|
pytestmark = []
|
||||||
|
|
||||||
if DJANGO_FILTER_INSTALLED:
|
if DJANGO_FILTER_INSTALLED:
|
||||||
|
@ -509,7 +513,7 @@ def test_should_query_filter_node_double_limit_raises():
|
||||||
a_choice=2
|
a_choice=2
|
||||||
)
|
)
|
||||||
r = Reporter.objects.create(
|
r = Reporter.objects.create(
|
||||||
first_name='John',
|
first_name='a',
|
||||||
last_name='Doe',
|
last_name='Doe',
|
||||||
email='johndoe@example.com',
|
email='johndoe@example.com',
|
||||||
a_choice=1
|
a_choice=1
|
||||||
|
@ -534,3 +538,137 @@ def test_should_query_filter_node_double_limit_raises():
|
||||||
assert str(result.errors[0]) == (
|
assert str(result.errors[0]) == (
|
||||||
'Received two sliced querysets (high mark) in the connection, please slice only in one.'
|
'Received two sliced querysets (high mark) in the connection, please slice only in one.'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def test_order_by_is_perserved():
|
||||||
|
class ReporterType(DjangoObjectType):
|
||||||
|
class Meta:
|
||||||
|
model = Reporter
|
||||||
|
interfaces = (Node, )
|
||||||
|
filter_fields = ()
|
||||||
|
|
||||||
|
class Query(ObjectType):
|
||||||
|
all_reporters = DjangoFilterConnectionField(ReporterType, reverse_order=Boolean())
|
||||||
|
|
||||||
|
def resolve_all_reporters(self, info, reverse_order=False, **args):
|
||||||
|
reporters = Reporter.objects.order_by('first_name')
|
||||||
|
|
||||||
|
if reverse_order:
|
||||||
|
return reporters.reverse()
|
||||||
|
|
||||||
|
return reporters
|
||||||
|
|
||||||
|
Reporter.objects.create(
|
||||||
|
first_name='b',
|
||||||
|
)
|
||||||
|
r = Reporter.objects.create(
|
||||||
|
first_name='a',
|
||||||
|
)
|
||||||
|
|
||||||
|
schema = Schema(query=Query)
|
||||||
|
query = '''
|
||||||
|
query NodeFilteringQuery {
|
||||||
|
allReporters(first: 1) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
firstName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
expected = {
|
||||||
|
'allReporters': {
|
||||||
|
'edges': [{
|
||||||
|
'node': {
|
||||||
|
'firstName': 'a',
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = schema.execute(query)
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
reverse_query = '''
|
||||||
|
query NodeFilteringQuery {
|
||||||
|
allReporters(first: 1, reverseOrder: true) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
firstName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
reverse_expected = {
|
||||||
|
'allReporters': {
|
||||||
|
'edges': [{
|
||||||
|
'node': {
|
||||||
|
'firstName': 'b',
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reverse_result = schema.execute(reverse_query)
|
||||||
|
|
||||||
|
assert not reverse_result.errors
|
||||||
|
assert reverse_result.data == reverse_expected
|
||||||
|
|
||||||
|
def test_annotation_is_perserved():
|
||||||
|
class ReporterType(DjangoObjectType):
|
||||||
|
full_name = String()
|
||||||
|
|
||||||
|
def resolve_full_name(instance, info, **args):
|
||||||
|
return instance.full_name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Reporter
|
||||||
|
interfaces = (Node, )
|
||||||
|
filter_fields = ()
|
||||||
|
|
||||||
|
class Query(ObjectType):
|
||||||
|
all_reporters = DjangoFilterConnectionField(ReporterType)
|
||||||
|
|
||||||
|
def resolve_all_reporters(self, info, **args):
|
||||||
|
return Reporter.objects.annotate(
|
||||||
|
full_name=Concat('first_name', Value(' '), 'last_name', output_field=TextField())
|
||||||
|
)
|
||||||
|
|
||||||
|
Reporter.objects.create(
|
||||||
|
first_name='John',
|
||||||
|
last_name='Doe',
|
||||||
|
)
|
||||||
|
|
||||||
|
schema = Schema(query=Query)
|
||||||
|
|
||||||
|
query = '''
|
||||||
|
query NodeFilteringQuery {
|
||||||
|
allReporters(first: 1) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
fullName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
expected = {
|
||||||
|
'allReporters': {
|
||||||
|
'edges': [{
|
||||||
|
'node': {
|
||||||
|
'fullName': 'John Doe',
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = schema.execute(query)
|
||||||
|
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == expected
|
|
@ -1,6 +1,6 @@
|
||||||
from mock import patch
|
from mock import patch
|
||||||
|
|
||||||
from graphene import Interface, ObjectType, Schema
|
from graphene import Interface, ObjectType, Schema, Connection, String
|
||||||
from graphene.relay import Node
|
from graphene.relay import Node
|
||||||
|
|
||||||
from .. import registry
|
from .. import registry
|
||||||
|
@ -17,11 +17,23 @@ class Reporter(DjangoObjectType):
|
||||||
model = ReporterModel
|
model = ReporterModel
|
||||||
|
|
||||||
|
|
||||||
|
class ArticleConnection(Connection):
|
||||||
|
'''Article Connection'''
|
||||||
|
test = String()
|
||||||
|
|
||||||
|
def resolve_test():
|
||||||
|
return 'test'
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class Article(DjangoObjectType):
|
class Article(DjangoObjectType):
|
||||||
'''Article description'''
|
'''Article description'''
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ArticleModel
|
model = ArticleModel
|
||||||
interfaces = (Node, )
|
interfaces = (Node, )
|
||||||
|
connection_class = ArticleConnection
|
||||||
|
|
||||||
|
|
||||||
class RootQuery(ObjectType):
|
class RootQuery(ObjectType):
|
||||||
|
@ -74,6 +86,7 @@ type Article implements Node {
|
||||||
type ArticleConnection {
|
type ArticleConnection {
|
||||||
pageInfo: PageInfo!
|
pageInfo: PageInfo!
|
||||||
edges: [ArticleEdge]!
|
edges: [ArticleEdge]!
|
||||||
|
test: String
|
||||||
}
|
}
|
||||||
|
|
||||||
type ArticleEdge {
|
type ArticleEdge {
|
||||||
|
|
|
@ -45,7 +45,7 @@ class DjangoObjectType(ObjectType):
|
||||||
@classmethod
|
@classmethod
|
||||||
def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=False,
|
def __init_subclass_with_meta__(cls, model=None, registry=None, skip_registry=False,
|
||||||
only_fields=(), exclude_fields=(), filter_fields=None, connection=None,
|
only_fields=(), exclude_fields=(), filter_fields=None, connection=None,
|
||||||
use_connection=None, interfaces=(), **options):
|
connection_class=None, use_connection=None, interfaces=(), **options):
|
||||||
assert is_valid_django_model(model), (
|
assert is_valid_django_model(model), (
|
||||||
'You need to pass a valid Django Model in {}.Meta, received "{}".'
|
'You need to pass a valid Django Model in {}.Meta, received "{}".'
|
||||||
).format(cls.__name__, model)
|
).format(cls.__name__, model)
|
||||||
|
@ -71,7 +71,11 @@ class DjangoObjectType(ObjectType):
|
||||||
|
|
||||||
if use_connection and not connection:
|
if use_connection and not connection:
|
||||||
# We create the connection automatically
|
# We create the connection automatically
|
||||||
connection = Connection.create_type('{}Connection'.format(cls.__name__), node=cls)
|
if not connection_class:
|
||||||
|
connection_class = Connection
|
||||||
|
|
||||||
|
connection = connection_class.create_type(
|
||||||
|
'{}Connection'.format(cls.__name__), node=cls)
|
||||||
|
|
||||||
if connection is not None:
|
if connection is not None:
|
||||||
assert issubclass(connection, Connection), (
|
assert issubclass(connection, Connection), (
|
||||||
|
|
Loading…
Reference in New Issue
Block a user