mirror of
https://github.com/graphql-python/graphene-django.git
synced 2025-06-08 07:33:14 +03:00
Merge branch 'master' into form_mutations
This commit is contained in:
commit
bb6da28008
|
@ -38,6 +38,12 @@ env:
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
|
- python: '3.4'
|
||||||
|
env: TEST_TYPE=build DJANGO_VERSION=2.0
|
||||||
|
- python: '3.5'
|
||||||
|
env: TEST_TYPE=build DJANGO_VERSION=2.0
|
||||||
|
- python: '3.6'
|
||||||
|
env: TEST_TYPE=build DJANGO_VERSION=2.0
|
||||||
- python: '2.7'
|
- python: '2.7'
|
||||||
env: TEST_TYPE=build DJANGO_VERSION=1.8
|
env: TEST_TYPE=build DJANGO_VERSION=1.8
|
||||||
- python: '2.7'
|
- python: '2.7'
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.db import models
|
||||||
|
|
||||||
class Character(models.Model):
|
class Character(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
ship = models.ForeignKey('Ship', blank=True, null=True, related_name='characters')
|
ship = models.ForeignKey('Ship', on_delete=models.CASCADE, blank=True, null=True, related_name='characters')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -13,7 +13,7 @@ class Character(models.Model):
|
||||||
|
|
||||||
class Faction(models.Model):
|
class Faction(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
hero = models.ForeignKey(Character)
|
hero = models.ForeignKey(Character, on_delete=models.CASCADE)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -21,7 +21,7 @@ class Faction(models.Model):
|
||||||
|
|
||||||
class Ship(models.Model):
|
class Ship(models.Model):
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
faction = models.ForeignKey(Faction, related_name='ships')
|
faction = models.ForeignKey(Faction, on_delete=models.CASCADE, related_name='ships')
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
|
@ -67,6 +67,10 @@ class DjangoConnectionField(ConnectionField):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def merge_querysets(cls, default_queryset, queryset):
|
def merge_querysets(cls, default_queryset, queryset):
|
||||||
|
if default_queryset.query.distinct and not queryset.query.distinct:
|
||||||
|
queryset = queryset.distinct()
|
||||||
|
elif queryset.query.distinct and not default_queryset.query.distinct:
|
||||||
|
default_queryset = default_queryset.distinct()
|
||||||
return queryset & default_queryset
|
return queryset & default_queryset
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -57,7 +57,11 @@ class GrapheneFilterSetMixin(BaseFilterSet):
|
||||||
Global IDs (the default implementation expects database
|
Global IDs (the default implementation expects database
|
||||||
primary keys)
|
primary keys)
|
||||||
"""
|
"""
|
||||||
rel = f.field.remote_field if hasattr(f.field, 'remote_field') else f.field.rel
|
try:
|
||||||
|
rel = f.field.remote_field
|
||||||
|
except AttributeError:
|
||||||
|
rel = f.field.rel
|
||||||
|
|
||||||
default = {
|
default = {
|
||||||
'name': name,
|
'name': name,
|
||||||
'label': capfirst(rel.related_name)
|
'label': capfirst(rel.related_name)
|
||||||
|
|
|
@ -85,12 +85,6 @@ def convert_form_field_to_id(field):
|
||||||
return ID(required=field.required)
|
return ID(required=field.required)
|
||||||
|
|
||||||
|
|
||||||
@convert_form_field.register(forms.DateField)
|
|
||||||
@convert_form_field.register(forms.DateTimeField)
|
|
||||||
def convert_form_field_to_datetime(field):
|
|
||||||
return DateTime(description=field.help_text, required=field.required)
|
|
||||||
|
|
||||||
|
|
||||||
@convert_form_field.register(forms.TimeField)
|
@convert_form_field.register(forms.TimeField)
|
||||||
def convert_form_field_to_time(field):
|
def convert_form_field_to_time(field):
|
||||||
return Time(description=field.help_text, required=field.required)
|
return Time(description=field.help_text, required=field.required)
|
||||||
|
|
|
@ -15,10 +15,14 @@ class Pet(models.Model):
|
||||||
|
|
||||||
class FilmDetails(models.Model):
|
class FilmDetails(models.Model):
|
||||||
location = models.CharField(max_length=30)
|
location = models.CharField(max_length=30)
|
||||||
film = models.OneToOneField('Film', related_name='details')
|
film = models.OneToOneField('Film', on_delete=models.CASCADE, related_name='details')
|
||||||
|
|
||||||
|
|
||||||
class Film(models.Model):
|
class Film(models.Model):
|
||||||
|
genre = models.CharField(max_length=2, help_text='Genre', choices=[
|
||||||
|
('do', 'Documentary'),
|
||||||
|
('ot', 'Other')
|
||||||
|
], default='ot')
|
||||||
reporters = models.ManyToManyField('Reporter',
|
reporters = models.ManyToManyField('Reporter',
|
||||||
related_name='films')
|
related_name='films')
|
||||||
|
|
||||||
|
@ -70,8 +74,8 @@ class Article(models.Model):
|
||||||
headline = models.CharField(max_length=100)
|
headline = models.CharField(max_length=100)
|
||||||
pub_date = models.DateField()
|
pub_date = models.DateField()
|
||||||
pub_date_time = models.DateTimeField()
|
pub_date_time = models.DateTimeField()
|
||||||
reporter = models.ForeignKey(Reporter, related_name='articles')
|
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE, related_name='articles')
|
||||||
editor = models.ForeignKey(Reporter, related_name='edited_articles_+')
|
editor = models.ForeignKey(Reporter, on_delete=models.CASCADE, related_name='edited_articles_+')
|
||||||
lang = models.CharField(max_length=2, help_text='Language', choices=[
|
lang = models.CharField(max_length=2, help_text='Language', choices=[
|
||||||
('es', 'Spanish'),
|
('es', 'Spanish'),
|
||||||
('en', 'English')
|
('en', 'English')
|
||||||
|
|
|
@ -5,6 +5,8 @@ from django.db import models
|
||||||
from django.utils.functional import SimpleLazyObject
|
from django.utils.functional import SimpleLazyObject
|
||||||
from py.test import raises
|
from py.test import raises
|
||||||
|
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
from graphene.relay import Node
|
from graphene.relay import Node
|
||||||
|
|
||||||
|
@ -17,6 +19,8 @@ from .models import (
|
||||||
Article,
|
Article,
|
||||||
CNNReporter,
|
CNNReporter,
|
||||||
Reporter,
|
Reporter,
|
||||||
|
Film,
|
||||||
|
FilmDetails,
|
||||||
)
|
)
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
|
@ -431,6 +435,60 @@ def test_should_query_node_filtering():
|
||||||
assert result.data == expected
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(not DJANGO_FILTER_INSTALLED,
|
||||||
|
reason="django-filter should be installed")
|
||||||
|
def test_should_query_node_filtering_with_distinct_queryset():
|
||||||
|
class FilmType(DjangoObjectType):
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Film
|
||||||
|
interfaces = (Node, )
|
||||||
|
filter_fields = ('genre',)
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
films = DjangoConnectionField(FilmType)
|
||||||
|
|
||||||
|
# def resolve_all_reporters_with_berlin_films(self, args, context, info):
|
||||||
|
# return Reporter.objects.filter(Q(films__film__location__contains="Berlin") | Q(a_choice=1))
|
||||||
|
|
||||||
|
def resolve_films(self, info, **args):
|
||||||
|
return Film.objects.filter(Q(details__location__contains="Berlin") | Q(genre__in=['ot'])).distinct()
|
||||||
|
|
||||||
|
f = Film.objects.create(
|
||||||
|
)
|
||||||
|
fd = FilmDetails.objects.create(
|
||||||
|
location="Berlin",
|
||||||
|
film=f
|
||||||
|
)
|
||||||
|
|
||||||
|
schema = graphene.Schema(query=Query)
|
||||||
|
query = '''
|
||||||
|
query NodeFilteringQuery {
|
||||||
|
films {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
genre
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
expected = {
|
||||||
|
'films': {
|
||||||
|
'edges': [{
|
||||||
|
'node': {
|
||||||
|
'genre': 'OT'
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result = schema.execute(query)
|
||||||
|
assert not result.errors
|
||||||
|
assert result.data == expected
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.skipif(not DJANGO_FILTER_INSTALLED,
|
@pytest.mark.skipif(not DJANGO_FILTER_INSTALLED,
|
||||||
reason="django-filter should be installed")
|
reason="django-filter should be installed")
|
||||||
def test_should_query_node_multiple_filtering():
|
def test_should_query_node_multiple_filtering():
|
||||||
|
|
Loading…
Reference in New Issue
Block a user