From 854aa4aa9ba37bc4619c860b5a258f1e68a9366d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 2 Nov 2016 21:41:25 -0700 Subject: [PATCH 01/23] Fixed tests --- graphene_django/tests/test_types.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 5c04651..5d65551 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -73,7 +73,7 @@ type Article implements Node { type ArticleConnection { pageInfo: PageInfo! - edges: [ArticleEdge] + edges: [ArticleEdge]! } type ArticleEdge { From 5289cd06d7b00e5ff9bc49f7180a38efa0e8713d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 2 Nov 2016 21:45:49 -0700 Subject: [PATCH 02/23] Improved choice Enum converter --- graphene_django/converter.py | 4 ++-- graphene_django/tests/test_types.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 22df6ca..70b364c 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -6,7 +6,7 @@ from graphene import (ID, Boolean, Dynamic, Enum, Field, Float, Int, List, from graphene.relay import is_node from graphene.types.datetime import DateTime from graphene.types.json import JSONString -from graphene.utils.str_converters import to_const +from graphene.utils.str_converters import to_camel_case, to_const from graphql import assert_valid_name from .compat import (ArrayField, HStoreField, JSONField, RangeField, @@ -41,7 +41,7 @@ def convert_django_field_with_choices(field, registry=None): choices = getattr(field, 'choices', None) if choices: meta = field.model._meta - name = '{}{}'.format(meta.object_name, field.name.capitalize()) + name = to_camel_case('{}_{}'.format(meta.object_name, field.name)) choices = list(get_choices(choices)) named_choices = [(c[0], c[1]) for c in choices] named_choices_descriptions = {c[0]: c[2] for c in choices} diff --git a/graphene_django/tests/test_types.py b/graphene_django/tests/test_types.py index 5d65551..c617fe4 100644 --- a/graphene_django/tests/test_types.py +++ b/graphene_django/tests/test_types.py @@ -110,11 +110,11 @@ type Reporter { lastName: String! email: String! pets: [Reporter] - aChoice: ReporterA_choice! + aChoice: ReporterAChoice! articles(before: String, after: String, first: Int, last: Int): ArticleConnection } -enum ReporterA_choice { +enum ReporterAChoice { A_1 A_2 } From 8749f5a6d8cf50a2feca4b8399e3c8db17073e56 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 14 Nov 2016 22:32:41 -0800 Subject: [PATCH 03/23] Updated travis to auto-upload PyPI versions. Fixed #41 --- .travis.yml | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1ac8f98..ed78404 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,19 +6,19 @@ python: - 3.5 - pypy before_install: - - | - if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then - export PYENV_ROOT="$HOME/.pyenv" - if [ -f "$PYENV_ROOT/bin/pyenv" ]; then - cd "$PYENV_ROOT" && git pull - else - rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT" - fi - export PYPY_VERSION="4.0.1" - "$PYENV_ROOT/bin/pyenv" install "pypy-$PYPY_VERSION" - virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" - source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" - fi +- | + if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then + export PYENV_ROOT="$HOME/.pyenv" + if [ -f "$PYENV_ROOT/bin/pyenv" ]; then + cd "$PYENV_ROOT" && git pull + else + rm -rf "$PYENV_ROOT" && git clone --depth 1 https://github.com/yyuu/pyenv.git "$PYENV_ROOT" + fi + export PYPY_VERSION="4.0.1" + "$PYENV_ROOT/bin/pyenv" install "pypy-$PYPY_VERSION" + virtualenv --python="$PYENV_ROOT/versions/pypy-$PYPY_VERSION/bin/python" "$HOME/virtualenvs/pypy-$PYPY_VERSION" + source "$HOME/virtualenvs/pypy-$PYPY_VERSION/bin/activate" + fi install: - | if [ "$TEST_TYPE" = build ]; then @@ -59,3 +59,10 @@ matrix: env: TEST_TYPE=build DJANGO_VERSION=1.9 - python: '2.7' env: TEST_TYPE=lint +deploy: + provider: pypi + user: syrusakbary + on: + tags: true + password: + secure: kymIFCEPUbkgRqe2NAXkWfxMmGRfWvWBOP6LIXdVdkOOkm91fU7bndPGrAjos+/7gN0Org609ZmHSlVXNMJUWcsL2or/x5LcADJ4cZDe+79qynuoRb9xs1Ri4O4SBAuVMZxuVJvs8oUzT2R11ql5vASSMtXgbX+ZDGpmPRVZStkCuXgOc4LBhbPKyl3OFy7UQFPgAEmy3Yjh4ZSKzlXheK+S6mmr60+DCIjpaA0BWPxYK9FUE0qm7JJbHLUbwsUP/QMp5MmGjwFisXCNsIe686B7QKRaiOw62eJc2R7He8AuEC8T9OM4kRwDlecSn8mMpkoSB7QWtlJ+6XdLrJFPNvtrOfgfzS9/96Qrw9WlOslk68hMlhJeRb0s2YUD8tiV3UUkvbL1mfFoS4SI9U+rojS55KhUEJWHg1w7DjoOPoZmaIL2ChRupmvrFYNAGae1cxwG3Urh+t3wYlN3gpKsRDe5GOT7Wm2tr0ad3McCpDGUwSChX59BAJXe/MoLxkKScTrMyR8yMxHOF0b4zpVn5l7xB/o2Ik4zavx5q/0rGBMK2D+5d+gpQogKShoquTPsZUwO7sB5hYeH2hqGqpeGzZtb76E2zZYd18pJ0FsBudm5+KWjYdZ+vbtGrLxdTXJ1EEtzVXm0lscykTpqUucbXSa51dhStJvW2xEEz6p3rHo= From cf27318e3c63f62e9b4fd840eb21d27263050fda Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 14 Nov 2016 22:33:58 -0800 Subject: [PATCH 04/23] Updated version to 1.1.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index d5787c7..9c55634 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import find_packages, setup setup( name='graphene-django', - version='1.0', + version='1.1.0', description='Graphene Django integration', long_description=open('README.rst').read(), From 96236408c52e5175388e5b8bef43dc5131cd4004 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 14 Nov 2016 22:34:49 -0800 Subject: [PATCH 05/23] Fixed lint issue --- graphene_django/compat.py | 1 + 1 file changed, 1 insertion(+) diff --git a/graphene_django/compat.py b/graphene_django/compat.py index 461dfef..f17f247 100644 --- a/graphene_django/compat.py +++ b/graphene_django/compat.py @@ -4,6 +4,7 @@ from django.db import models class MissingType(object): pass + try: DurationField = models.DurationField UUIDField = models.UUIDField From d8567f1c58cb87527fa55d9dc9ace9d7ac444047 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Mon, 14 Nov 2016 23:07:45 -0800 Subject: [PATCH 06/23] Fixed JSONField import only in Django 1.9+. Fixed #40 --- graphene_django/compat.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/graphene_django/compat.py b/graphene_django/compat.py index f17f247..49ea68f 100644 --- a/graphene_django/compat.py +++ b/graphene_django/compat.py @@ -22,6 +22,13 @@ except: try: # Postgres fields are only available in Django 1.8+ - from django.contrib.postgres.fields import ArrayField, HStoreField, JSONField, RangeField + from django.contrib.postgres.fields import ArrayField, HStoreField, RangeField except ImportError: ArrayField, HStoreField, JSONField, RangeField = (MissingType, ) * 4 + + +try: + # Postgres fields are only available in Django 1.9+ + from django.contrib.postgres.fields import JSONField +except ImportError: + JSONField = MissingType From 48993ddca0a7fa16dfb0888a808eea88accb3d4c Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 01:01:32 -0800 Subject: [PATCH 07/23] Fixed order_by --- .travis.yml | 13 +++++++------ graphene_django/filter/utils.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index ed78404..10fcb82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,8 +22,9 @@ before_install: install: - | if [ "$TEST_TYPE" = build ]; then - pip install pytest==3.0.2 pytest-cov pytest-benchmark coveralls six pytest-django==2.9.1 mock django-filter pip install django==$DJANGO_VERSION + pip install pytest==3.0.2 pytest-cov pytest-benchmark coveralls six pytest-django==2.9.1 mock + pip install django==$DJANGO_FILTER_VERSION pip install -e . python setup.py develop elif [ "$TEST_TYPE" = lint ]; then @@ -45,18 +46,18 @@ after_success: fi env: matrix: - - TEST_TYPE=build + - TEST_TYPE=build DJANGO_VERSION=1.10 DJANGO_FILTER_VERSION=1.0.0 matrix: fast_finish: true include: - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.6 + env: TEST_TYPE=build DJANGO_VERSION=1.6 DJANGO_FILTER_VERSION=0.15.3 - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.7 + env: TEST_TYPE=build DJANGO_VERSION=1.7 DJANGO_FILTER_VERSION=0.15.3 - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.8 + env: TEST_TYPE=build DJANGO_VERSION=1.8 DJANGO_FILTER_VERSION=0.15.3 - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.9 + env: TEST_TYPE=build DJANGO_VERSION=1.9 DJANGO_FILTER_VERSION=1.0.0 - python: '2.7' env: TEST_TYPE=lint deploy: diff --git a/graphene_django/filter/utils.py b/graphene_django/filter/utils.py index 3720dd8..20e271a 100644 --- a/graphene_django/filter/utils.py +++ b/graphene_django/filter/utils.py @@ -19,7 +19,7 @@ def get_filtering_args_from_filterset(filterset_class, type): args[name] = field_type # Also add the 'order_by' field - if filterset_class._meta.order_by: + if getattr(filterset_class._meta, 'order_by', None): args[filterset_class.order_by_field] = String() return args From 8dfe7bbcf5765d767d7db68ebb9a22c940cea9b6 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 02:15:05 -0800 Subject: [PATCH 08/23] Remove filter order_by as Django Filters have deprecated it in 1.0 --- graphene_django/filter/__init__.py | 4 +-- graphene_django/filter/fields.py | 17 ++++----- graphene_django/filter/filterset.py | 40 +++------------------ graphene_django/filter/tests/filters.py | 8 +++-- graphene_django/filter/tests/test_fields.py | 18 ++++------ graphene_django/filter/utils.py | 4 --- graphene_django/types.py | 1 - setup.py | 2 +- 8 files changed, 26 insertions(+), 68 deletions(-) diff --git a/graphene_django/filter/__init__.py b/graphene_django/filter/__init__.py index 71616b6..24fae60 100644 --- a/graphene_django/filter/__init__.py +++ b/graphene_django/filter/__init__.py @@ -8,7 +8,7 @@ if not DJANGO_FILTER_INSTALLED: ) else: from .fields import DjangoFilterConnectionField - from .filterset import GrapheneFilterSet, GlobalIDFilter, GlobalIDMultipleChoiceFilter + from .filterset import GlobalIDFilter, GlobalIDMultipleChoiceFilter - __all__ = ['DjangoFilterConnectionField', 'GrapheneFilterSet', + __all__ = ['DjangoFilterConnectionField', 'GlobalIDFilter', 'GlobalIDMultipleChoiceFilter'] diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index bd4b44d..59c6044 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -1,20 +1,19 @@ from functools import partial +from django_filters import OrderingFilter + from ..fields import DjangoConnectionField from .utils import get_filtering_args_from_filterset, get_filterset_class class DjangoFilterConnectionField(DjangoConnectionField): - def __init__(self, type, fields=None, order_by=None, - extra_filter_meta=None, filterset_class=None, - *args, **kwargs): + def __init__(self, type, fields=None, extra_filter_meta=None, + filterset_class=None, *args, **kwargs): - self.order_by = order_by or type._meta.filter_order_by self.fields = fields or type._meta.filter_fields meta = dict(model=type._meta.model, - fields=self.fields, - order_by=self.order_by) + fields=self.fields) if extra_filter_meta: meta.update(extra_filter_meta) self.filterset_class = get_filterset_class(filterset_class, **meta) @@ -27,12 +26,8 @@ class DjangoFilterConnectionField(DjangoConnectionField): def connection_resolver(resolver, connection, default_manager, filterset_class, filtering_args, root, args, context, info): filter_kwargs = {k: v for k, v in args.items() if k in filtering_args} - order = args.get('order_by', None) qs = default_manager.get_queryset() - if order: - qs = qs.order_by(order) - qs = filterset_class(data=filter_kwargs, queryset=qs) - + qs = filterset_class(data=filter_kwargs, queryset=qs).qs return DjangoConnectionField.connection_resolver(resolver, connection, qs, root, args, context, info) def get_resolver(self, parent_resolver): diff --git a/graphene_django/filter/filterset.py b/graphene_django/filter/filterset.py index 6df50ce..bbac0be 100644 --- a/graphene_django/filter/filterset.py +++ b/graphene_django/filter/filterset.py @@ -5,7 +5,7 @@ from django.conf import settings from django.db import models from django.utils.text import capfirst from django_filters import Filter, MultipleChoiceFilter -from django_filters.filterset import FilterSet, FilterSetMetaclass +from django_filters.filterset import BaseFilterSet, FilterSet, FilterSetMetaclass from django_filters.filterset import FILTER_FOR_DBFIELD_DEFAULTS from graphql_relay.node.node import from_global_id @@ -29,9 +29,6 @@ class GlobalIDMultipleChoiceFilter(MultipleChoiceFilter): return super(GlobalIDMultipleChoiceFilter, self).filter(qs, gids) -ORDER_BY_FIELD = getattr(settings, 'GRAPHENE_ORDER_BY_FIELD', 'order_by') - - GRAPHENE_FILTER_SET_OVERRIDES = { models.AutoField: { 'filter_class': GlobalIDFilter, @@ -48,25 +45,7 @@ GRAPHENE_FILTER_SET_OVERRIDES = { } -# Only useful for Django-filter 0.14-, not necessary in latest version 0.15+ -class GrapheneFilterSetMetaclass(FilterSetMetaclass): - - def __new__(cls, name, bases, attrs): - new_class = super(GrapheneFilterSetMetaclass, cls).__new__(cls, name, bases, attrs) - # Customise the filter_overrides for Graphene - if hasattr(new_class, '_meta') and hasattr(new_class._meta, 'filter_overrides'): - filter_overrides = new_class._meta.filter_overrides - else: - filter_overrides = new_class.filter_overrides - - for k, v in GRAPHENE_FILTER_SET_OVERRIDES.items(): - filter_overrides.setdefault(k, v) - - return new_class - - -class GrapheneFilterSetMixin(object): - order_by_field = ORDER_BY_FIELD +class GrapheneFilterSetMixin(BaseFilterSet): FILTER_DEFAULTS = dict(itertools.chain( FILTER_FOR_DBFIELD_DEFAULTS.items(), GRAPHENE_FILTER_SET_OVERRIDES.items() @@ -93,26 +72,17 @@ class GrapheneFilterSetMixin(object): return GlobalIDFilter(**default) -class GrapheneFilterSet(six.with_metaclass(GrapheneFilterSetMetaclass, GrapheneFilterSetMixin, FilterSet)): - """ Base class for FilterSets used by Graphene - - You shouldn't usually need to use this class. The - DjangoFilterConnectionField will wrap FilterSets with this class as - necessary - """ - - def setup_filterset(filterset_class): """ Wrap a provided filterset in Graphene-specific functionality """ return type( 'Graphene{}'.format(filterset_class.__name__), - (six.with_metaclass(GrapheneFilterSetMetaclass, GrapheneFilterSetMixin, filterset_class),), + (filterset_class, GrapheneFilterSetMixin), {}, ) -def custom_filterset_factory(model, filterset_base_class=GrapheneFilterSet, +def custom_filterset_factory(model, filterset_base_class=FilterSet, **meta): """ Create a filterset for the given model using the provided meta data """ @@ -122,7 +92,7 @@ def custom_filterset_factory(model, filterset_base_class=GrapheneFilterSet, meta_class = type(str('Meta'), (object,), meta) filterset = type( str('%sFilterSet' % model._meta.object_name), - (filterset_base_class,), + (filterset_base_class, GrapheneFilterSetMixin), { 'Meta': meta_class } diff --git a/graphene_django/filter/tests/filters.py b/graphene_django/filter/tests/filters.py index bb2f657..4a3fbaa 100644 --- a/graphene_django/filter/tests/filters.py +++ b/graphene_django/filter/tests/filters.py @@ -1,4 +1,5 @@ import django_filters +from django_filters import OrderingFilter from graphene_django.tests.models import Article, Pet, Reporter @@ -12,7 +13,8 @@ class ArticleFilter(django_filters.FilterSet): 'pub_date': ['gt', 'lt', 'exact'], 'reporter': ['exact'], } - order_by = False + + order_by = OrderingFilter(fields=('pub_date',)) class ReporterFilter(django_filters.FilterSet): @@ -20,7 +22,8 @@ class ReporterFilter(django_filters.FilterSet): class Meta: model = Reporter fields = ['first_name', 'last_name', 'email', 'pets'] - order_by = True + + order_by = OrderingFilter(fields=('pub_date',)) class PetFilter(django_filters.FilterSet): @@ -28,4 +31,3 @@ class PetFilter(django_filters.FilterSet): class Meta: model = Pet fields = ['name'] - order_by = False diff --git a/graphene_django/filter/tests/test_fields.py b/graphene_django/filter/tests/test_fields.py index ab3d677..e6ac3e4 100644 --- a/graphene_django/filter/tests/test_fields.py +++ b/graphene_django/filter/tests/test_fields.py @@ -27,6 +27,7 @@ class ArticleNode(DjangoObjectType): class Meta: model = Article interfaces = (Node, ) + filter_fields = ('headline', ) class ReporterNode(DjangoObjectType): @@ -110,8 +111,8 @@ def test_filter_explicit_filterset_orderable(): def test_filter_shortcut_filterset_orderable_true(): - field = DjangoFilterConnectionField(ReporterNode, order_by=True) - assert_orderable(field) + field = DjangoFilterConnectionField(ReporterNode) + assert_not_orderable(field) # def test_filter_shortcut_filterset_orderable_headline(): @@ -126,9 +127,9 @@ def test_filter_explicit_filterset_not_orderable(): def test_filter_shortcut_filterset_extra_meta(): field = DjangoFilterConnectionField(ArticleNode, extra_filter_meta={ - 'order_by': True + 'exclude': ('headline', ) }) - assert_orderable(field) + assert 'headline' not in field.filterset_class.get_fields() def test_filter_filterset_information_on_meta(): @@ -138,11 +139,10 @@ def test_filter_filterset_information_on_meta(): model = Reporter interfaces = (Node, ) filter_fields = ['first_name', 'articles'] - filter_order_by = True field = DjangoFilterConnectionField(ReporterFilterNode) assert_arguments(field, 'first_name', 'articles') - assert_orderable(field) + assert_not_orderable(field) def test_filter_filterset_information_on_meta_related(): @@ -152,7 +152,6 @@ def test_filter_filterset_information_on_meta_related(): model = Reporter interfaces = (Node, ) filter_fields = ['first_name', 'articles'] - filter_order_by = True class ArticleFilterNode(DjangoObjectType): @@ -160,7 +159,6 @@ def test_filter_filterset_information_on_meta_related(): model = Article interfaces = (Node, ) filter_fields = ['headline', 'reporter'] - filter_order_by = True class Query(ObjectType): all_reporters = DjangoFilterConnectionField(ReporterFilterNode) @@ -171,7 +169,7 @@ def test_filter_filterset_information_on_meta_related(): schema = Schema(query=Query) articles_field = ReporterFilterNode._meta.fields['articles'].get_type() assert_arguments(articles_field, 'headline', 'reporter') - assert_orderable(articles_field) + assert_not_orderable(articles_field) def test_filter_filterset_related_results(): @@ -181,7 +179,6 @@ def test_filter_filterset_related_results(): model = Reporter interfaces = (Node, ) filter_fields = ['first_name', 'articles'] - filter_order_by = True class ArticleFilterNode(DjangoObjectType): @@ -189,7 +186,6 @@ def test_filter_filterset_related_results(): interfaces = (Node, ) model = Article filter_fields = ['headline', 'reporter'] - filter_order_by = True class Query(ObjectType): all_reporters = DjangoFilterConnectionField(ReporterFilterNode) diff --git a/graphene_django/filter/utils.py b/graphene_django/filter/utils.py index 20e271a..06af649 100644 --- a/graphene_django/filter/utils.py +++ b/graphene_django/filter/utils.py @@ -18,10 +18,6 @@ def get_filtering_args_from_filterset(filterset_class, type): field_type.description = filter_field.label args[name] = field_type - # Also add the 'order_by' field - if getattr(filterset_class._meta, 'order_by', None): - args[filterset_class.order_by_field] = String() - return args diff --git a/graphene_django/types.py b/graphene_django/types.py index 1973a85..8174f05 100644 --- a/graphene_django/types.py +++ b/graphene_django/types.py @@ -65,7 +65,6 @@ class DjangoObjectTypeMeta(ObjectTypeMeta): # we allow more attributes in Meta defaults.update( filter_fields=(), - filter_order_by=(), ) options = Options( diff --git a/setup.py b/setup.py index 9c55634..4acd947 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setup( 'pytest-runner', ], tests_require=[ - 'django-filter>=0.10.0', + 'django-filter>=1.0.0', 'pytest', 'pytest-django==2.9.1', 'mock', From 2e1f1544414e403df1edb446b9575fd73e2aef13 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 02:17:48 -0800 Subject: [PATCH 09/23] Fixed travis build --- .travis.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 10fcb82..3e21ae5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,9 +22,8 @@ before_install: install: - | if [ "$TEST_TYPE" = build ]; then + pip install pytest==3.0.2 pytest-cov pytest-benchmark coveralls six pytest-django==2.9.1 mock django-filter pip install django==$DJANGO_VERSION - pip install pytest==3.0.2 pytest-cov pytest-benchmark coveralls six pytest-django==2.9.1 mock - pip install django==$DJANGO_FILTER_VERSION pip install -e . python setup.py develop elif [ "$TEST_TYPE" = lint ]; then @@ -46,18 +45,18 @@ after_success: fi env: matrix: - - TEST_TYPE=build DJANGO_VERSION=1.10 DJANGO_FILTER_VERSION=1.0.0 + - TEST_TYPE=build DJANGO_VERSION=1.10 matrix: fast_finish: true include: - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.6 DJANGO_FILTER_VERSION=0.15.3 + env: TEST_TYPE=build DJANGO_VERSION=1.6 - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.7 DJANGO_FILTER_VERSION=0.15.3 + env: TEST_TYPE=build DJANGO_VERSION=1.7 - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.8 DJANGO_FILTER_VERSION=0.15.3 + env: TEST_TYPE=build DJANGO_VERSION=1.8 - python: '2.7' - env: TEST_TYPE=build DJANGO_VERSION=1.9 DJANGO_FILTER_VERSION=1.0.0 + env: TEST_TYPE=build DJANGO_VERSION=1.9 - python: '2.7' env: TEST_TYPE=lint deploy: From b3fbac5818981dc4f5e7a3266880874871691f60 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 02:28:21 -0800 Subject: [PATCH 10/23] Fixed tests --- graphene_django/filter/tests/test_fields.py | 30 +++++++++++---------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/graphene_django/filter/tests/test_fields.py b/graphene_django/filter/tests/test_fields.py index e6ac3e4..63c9e37 100644 --- a/graphene_django/filter/tests/test_fields.py +++ b/graphene_django/filter/tests/test_fields.py @@ -11,6 +11,7 @@ from graphene_django.tests.models import Article, Pet, Reporter from graphene_django.utils import DJANGO_FILTER_INSTALLED pytestmark = [] + if DJANGO_FILTER_INSTALLED: import django_filters from graphene_django.filter import (GlobalIDFilter, DjangoFilterConnectionField, @@ -22,28 +23,29 @@ else: pytestmark.append(pytest.mark.django_db) -class ArticleNode(DjangoObjectType): +if DJANGO_FILTER_INSTALLED: + class ArticleNode(DjangoObjectType): - class Meta: - model = Article - interfaces = (Node, ) - filter_fields = ('headline', ) + class Meta: + model = Article + interfaces = (Node, ) + filter_fields = ('headline', ) -class ReporterNode(DjangoObjectType): + class ReporterNode(DjangoObjectType): - class Meta: - model = Reporter - interfaces = (Node, ) + class Meta: + model = Reporter + interfaces = (Node, ) -class PetNode(DjangoObjectType): + class PetNode(DjangoObjectType): - class Meta: - model = Pet - interfaces = (Node, ) + class Meta: + model = Pet + interfaces = (Node, ) -# schema = Schema() + # schema = Schema() def get_args(field): From 9216772315660be54f2e40f0ca495b1afa96f348 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 02:30:14 -0800 Subject: [PATCH 11/23] Removed unused imports --- graphene_django/filter/fields.py | 2 -- graphene_django/filter/filterset.py | 4 +--- graphene_django/filter/utils.py | 2 -- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/graphene_django/filter/fields.py b/graphene_django/filter/fields.py index 59c6044..defcfc1 100644 --- a/graphene_django/filter/fields.py +++ b/graphene_django/filter/fields.py @@ -1,7 +1,5 @@ from functools import partial -from django_filters import OrderingFilter - from ..fields import DjangoConnectionField from .utils import get_filtering_args_from_filterset, get_filterset_class diff --git a/graphene_django/filter/filterset.py b/graphene_django/filter/filterset.py index bbac0be..c716b05 100644 --- a/graphene_django/filter/filterset.py +++ b/graphene_django/filter/filterset.py @@ -1,11 +1,9 @@ import itertools -import six -from django.conf import settings from django.db import models from django.utils.text import capfirst from django_filters import Filter, MultipleChoiceFilter -from django_filters.filterset import BaseFilterSet, FilterSet, FilterSetMetaclass +from django_filters.filterset import BaseFilterSet, FilterSet from django_filters.filterset import FILTER_FOR_DBFIELD_DEFAULTS from graphql_relay.node.node import from_global_id diff --git a/graphene_django/filter/utils.py b/graphene_django/filter/utils.py index 06af649..6b938ce 100644 --- a/graphene_django/filter/utils.py +++ b/graphene_django/filter/utils.py @@ -1,7 +1,5 @@ import six -from graphene import String - from .filterset import custom_filterset_factory, setup_filterset From 9d35b766970f9dd38fc90e2d5338dc363430d778 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 02:32:52 -0800 Subject: [PATCH 12/23] Remove order_by in docs --- docs/filtering.rst | 39 +-------------------------------------- docs/tutorial.rst | 2 -- 2 files changed, 1 insertion(+), 40 deletions(-) diff --git a/docs/filtering.rst b/docs/filtering.rst index f2ea0e1..f6ad882 100644 --- a/docs/filtering.rst +++ b/docs/filtering.rst @@ -91,50 +91,13 @@ Which you could query as follows: } } -Orderable fields ----------------- - -Ordering can also be specified using ``filter_order_by``. Like -``filter_fields``, this value is also passed directly to -``django-filter`` as the ``order_by`` field. For full details see the -`order\_by -documentation `__. - -For example: - -.. code:: python - - class AnimalNode(DjangoObjectType): - class Meta: - model = Animal - filter_fields = ['name', 'genus', 'is_domesticated'] - # Either a tuple/list of fields upon which ordering is allowed, or - # True to allow filtering on all fields specified in filter_fields - filter_order_by = True - interfaces = (relay.Node, ) - -You can then control the ordering via the ``orderBy`` argument: - -.. code:: - - query { - allAnimals(orderBy: "name") { - edges { - node { - id, - name - } - } - } - } - Custom Filtersets ----------------- By default Graphene provides easy access to the most commonly used features of ``django-filter``. This is done by transparently creating a ``django_filters.FilterSet`` class for you and passing in the values for -``filter_fields`` and ``filter_order_by``. +``filter_fields``. However, you may find this to be insufficient. In these cases you can create your own ``Filterset`` as follows: diff --git a/docs/tutorial.rst b/docs/tutorial.rst index e1537a3..cd201b9 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -98,7 +98,6 @@ Create ``cookbook/ingredients/schema.py`` and type the following: class Meta: model = Category filter_fields = ['name', 'ingredients'] - filter_order_by = ['name'] interfaces = (relay.Node, ) @@ -112,7 +111,6 @@ Create ``cookbook/ingredients/schema.py`` and type the following: 'category': ['exact'], 'category__name': ['exact'], } - filter_order_by = ['name', 'category__name'] interfaces = (relay.Node, ) From c60c1430a7f2e478910add2fd644a7d11d1cfdbc Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 23 Nov 2016 02:43:58 -0800 Subject: [PATCH 13/23] Updated version to 1.2.0 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 4acd947..e75a4a9 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import find_packages, setup setup( name='graphene-django', - version='1.1.0', + version='1.2.0', description='Graphene Django integration', long_description=open('README.rst').read(), From 91365ff670939e9dbbf4e1dd187a6738fe8d4345 Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Wed, 23 Nov 2016 11:29:04 -0500 Subject: [PATCH 14/23] added timefield support --- graphene_django/converter.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 70b364c..37114b2 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -4,7 +4,7 @@ from django.utils.encoding import force_text from graphene import (ID, Boolean, Dynamic, Enum, Field, Float, Int, List, NonNull, String) from graphene.relay import is_node -from graphene.types.datetime import DateTime +from graphene.types.datetime import DateTime, Time from graphene.types.json import JSONString from graphene.utils.str_converters import to_camel_case, to_const from graphql import assert_valid_name @@ -112,6 +112,11 @@ def convert_date_to_string(field, registry=None): return DateTime(description=field.help_text, required=not field.null) +@convert_django_field.register(models.TimeField) +def convert_date_to_string(field, registry=None): + return Time(description=field.help_text, required=not field.null) + + @convert_django_field.register(models.OneToOneRel) def convert_onetoone_field_to_djangomodel(field, registry=None): model = get_related_model(field) From 509645d3bd678cba816455df0a75c42b8d2a569e Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Wed, 23 Nov 2016 12:07:40 -0500 Subject: [PATCH 15/23] added time field test --- graphene_django/tests/test_converter.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index 3467ed7..ce5a961 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -5,7 +5,7 @@ from py.test import raises import graphene from graphene.relay import ConnectionField, Node -from graphene.types.datetime import DateTime +from graphene.types.datetime import DateTime, Time from graphene.types.json import JSONString from ..compat import (ArrayField, HStoreField, JSONField, MissingType, @@ -44,6 +44,10 @@ def test_should_date_convert_string(): assert_conversion(models.DateField, DateTime) +def test_should_time_convert_string(): + assert_conversion(models.TimeField, Time) + + def test_should_char_convert_string(): assert_conversion(models.CharField, graphene.String) From 402cd645e896e42b1c7134ae4d7b82248cb96803 Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Wed, 23 Nov 2016 12:24:53 -0500 Subject: [PATCH 16/23] added time field test --- graphene_django/tests/test_converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/tests/test_converter.py b/graphene_django/tests/test_converter.py index ce5a961..69be406 100644 --- a/graphene_django/tests/test_converter.py +++ b/graphene_django/tests/test_converter.py @@ -16,7 +16,7 @@ from ..types import DjangoObjectType from .models import Article, Film, FilmDetails, Reporter -# from graphene.core.types.custom_scalars import DateTime, JSONString +# from graphene.core.types.custom_scalars import DateTime, Time, JSONString def assert_conversion(django_field, graphene_field, *args, **kwargs): From 10699c0b6b0f6854661241eb2a2ccce63c1422b1 Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Wed, 23 Nov 2016 12:25:59 -0500 Subject: [PATCH 17/23] added time field --- graphene_django/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/converter.py b/graphene_django/converter.py index 37114b2..706d968 100644 --- a/graphene_django/converter.py +++ b/graphene_django/converter.py @@ -113,7 +113,7 @@ def convert_date_to_string(field, registry=None): @convert_django_field.register(models.TimeField) -def convert_date_to_string(field, registry=None): +def convert_time_to_string(field, registry=None): return Time(description=field.help_text, required=not field.null) From 0b76e1abacfdbe7667f7f34cd579532fbbedfcb0 Mon Sep 17 00:00:00 2001 From: Paul Bailey Date: Mon, 28 Nov 2016 14:25:41 -0500 Subject: [PATCH 18/23] updated dependency --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e75a4a9..8b03620 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ setup( install_requires=[ 'six>=1.10.0', - 'graphene>=1.0', + 'graphene>=1.1.2', 'Django>=1.6.0', 'iso8601', 'singledispatch>=3.4.0.3', From 22b33214a7ba256c3c90a92177061f1f435a3961 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 1 Dec 2016 21:49:58 -0800 Subject: [PATCH 19/23] Fixed Cookbook. Fixed #68 --- examples/cookbook/cookbook/ingredients/schema.py | 2 -- examples/cookbook/cookbook/recipes/schema.py | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/cookbook/cookbook/ingredients/schema.py b/examples/cookbook/cookbook/ingredients/schema.py index 5d9a9a5..b8b3c12 100644 --- a/examples/cookbook/cookbook/ingredients/schema.py +++ b/examples/cookbook/cookbook/ingredients/schema.py @@ -12,7 +12,6 @@ class CategoryNode(DjangoObjectType): model = Category interfaces = (Node, ) filter_fields = ['name', 'ingredients'] - filter_order_by = ['name'] class IngredientNode(DjangoObjectType): @@ -27,7 +26,6 @@ class IngredientNode(DjangoObjectType): 'category': ['exact'], 'category__name': ['exact'], } - filter_order_by = ['name', 'category__name'] class Query(AbstractType): diff --git a/examples/cookbook/cookbook/recipes/schema.py b/examples/cookbook/cookbook/recipes/schema.py index 56379ab..35a21de 100644 --- a/examples/cookbook/cookbook/recipes/schema.py +++ b/examples/cookbook/cookbook/recipes/schema.py @@ -9,7 +9,7 @@ class RecipeNode(DjangoObjectType): model = Recipe interfaces = (Node, ) filter_fields = ['title','amounts'] - filter_order_by = ['title'] + class RecipeIngredientNode(DjangoObjectType): @@ -22,7 +22,7 @@ class RecipeIngredientNode(DjangoObjectType): 'recipe': ['exact'], 'recipe__title': ['icontains'], } - filter_order_by = ['ingredient__name', 'recipe__title',] + class Query(AbstractType): recipe = Node.Field(RecipeNode) From b16cb69000667cefccedbf6c8db047f6fc7220b5 Mon Sep 17 00:00:00 2001 From: Patrick Sanders Date: Sat, 3 Dec 2016 11:08:25 -0500 Subject: [PATCH 20/23] Fix broken link in cookbook schema --- examples/cookbook/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cookbook/README.md b/examples/cookbook/README.md index 1fdae7d..018c584 100644 --- a/examples/cookbook/README.md +++ b/examples/cookbook/README.md @@ -60,5 +60,5 @@ Now you should be ready to start the server: Now head on over to [http://127.0.0.1:8000/graphql](http://127.0.0.1:8000/graphql) and run some queries! -(See the [Graphene-Django Tutorial](http://docs.graphene-python.org/projects/django/en/latest/tutorial.html#testing-our-graphql-schema) +(See the [Graphene-Django Tutorial](http://docs.graphene-python.org/projects/django/en/latest/tutorial#testing-our-graphql-schema) for some example queries) From 85da376333adfc1edc9b62bd0140bde40d6e9b4c Mon Sep 17 00:00:00 2001 From: Thierry Guillemot Date: Mon, 5 Dec 2016 10:59:06 +0100 Subject: [PATCH 21/23] Fix the setup of the cookbook example `ingredients` and `recipes` from [examples/cookbook](https://github.com/graphql-python/graphene-django/tree/master/examples/cookbook) are included in cookbook/cookbook. By following the tutorial `ingredients` and `recipes` are in `cookbook/`. Two possibilities : 1) There is a mistake in the doc and I can correct it by adding a `cd cookbook` (as done by the PR) 2) Correct the [examples/cookbook](https://github.com/graphql-python/graphene-django/tree/master/examples/cookbook). Solution 1 is easier but I prefer the solution 2 because it is closer of what is done in the [django tutorial](https://docs.djangoproject.com/en/1.10/intro/tutorial01/). --- docs/tutorial.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/tutorial.rst b/docs/tutorial.rst index cd201b9..56c492d 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -31,6 +31,7 @@ We will setup the project, create the following: # Set up a new project with a single application django-admin.py startproject cookbook . # Note the trailing '.' character + cd cookbook django-admin.py startapp ingredients Now sync your database for the first time: From 3f139da7ae531f33b8b75aabcca8794dbdfa7a23 Mon Sep 17 00:00:00 2001 From: Thierry Guillemot Date: Mon, 5 Dec 2016 11:01:49 +0100 Subject: [PATCH 22/23] Fix Post name attribute The `PostNode` class uses as model Post which does not have any field `title` --- docs/authorization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/authorization.rst b/docs/authorization.rst index 89c2059..9ee7d0a 100644 --- a/docs/authorization.rst +++ b/docs/authorization.rst @@ -12,7 +12,7 @@ Let's use a simple example model. from django.db import models class Post(models.Model): - name = models.CharField(max_length=100) + title = models.CharField(max_length=100) content = models.TextField() published = models.BooleanField(default=False) owner = models.ForeignKey('auth.User') From 4246ceaa8583861e8cf660a47878aae55a803add Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 16 Dec 2016 00:27:33 -0800 Subject: [PATCH 23/23] Updated version to 1.2.1 --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8b03620..7a4eaa7 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import find_packages, setup setup( name='graphene-django', - version='1.2.0', + version='1.2.1', description='Graphene Django integration', long_description=open('README.rst').read(), @@ -33,7 +33,7 @@ setup( install_requires=[ 'six>=1.10.0', - 'graphene>=1.1.2', + 'graphene>=1.1.3', 'Django>=1.6.0', 'iso8601', 'singledispatch>=3.4.0.3',