Improved python syntax and sorts (pep8). Improved Readme

This commit is contained in:
Syrus Akbary 2016-09-17 17:09:56 -07:00
parent 0434899b4e
commit 4e23c3ccf6
27 changed files with 132 additions and 69 deletions

2
.coveragerc Normal file
View File

@ -0,0 +1,2 @@
[run]
omit = */tests/*,graphene_django/debug/sql/*

View File

@ -3,20 +3,10 @@ Please read [UPGRADE-v1.0.md](https://github.com/graphql-python/graphene/blob/ma
---
# ![Graphene Logo](http://graphene-python.org/favicon.png) [Graphene-Django](http://graphene-python.org) [![Build Status](https://travis-ci.org/graphql-python/graphene-django.svg?branch=master)](https://travis-ci.org/graphql-python/graphene-django) [![PyPI version](https://badge.fury.io/py/graphene-django.svg)](https://badge.fury.io/py/graphene-django) [![Coverage Status](https://coveralls.io/repos/graphql-python/graphene-django/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-python/graphene-django?branch=master)
# ![Graphene Logo](http://graphene-python.org/favicon.png) Graphene-Django [![Build Status](https://travis-ci.org/graphql-python/graphene-django.svg?branch=master)](https://travis-ci.org/graphql-python/graphene-django) [![PyPI version](https://badge.fury.io/py/graphene-django.svg)](https://badge.fury.io/py/graphene-django) [![Coverage Status](https://coveralls.io/repos/graphql-python/graphene-django/badge.svg?branch=master&service=github)](https://coveralls.io/github/graphql-python/graphene-django?branch=master)
[Graphene](http://graphene-python.org) is a Python library for building GraphQL schemas/types fast and easily.
- **Easy to use:** Graphene helps you use GraphQL in Python without effort.
- **Relay:** Graphene has builtin support for Relay
- **Django:** Automatic *Django model* mapping to Graphene Types. Check a fully working [Django](http://github.com/graphql-python/swapi-graphene) implementation
Graphene also supports *SQLAlchemy*!
*What is supported in this Python version?* **Everything**: Interfaces, ObjectTypes, Scalars, Unions and Relay (Nodes, Connections), in addition to queries, mutations and subscriptions.
**NEW**!: [Try graphene online](http://graphene-python.org/playground/)
A [Django](https://www.djangoproject.com/) integration for [Graphene](http://graphene-python.org/).
## Installation
@ -28,30 +18,50 @@ pip install "graphene-django>=1.0.dev"
## Examples
Here is one example for get you started:
Here is a simple Django model:
```python
from django.db import models
from graphene_django import DjangoObjectType
class UserModel(models.Model):
name = models.CharField(max_length=100)
last_name = models.CharField(max_length=100)
```
To create a GraphQL schema for it you simply have to write the following:
```python
from graphene_django import DjangoObjectType
class User(DjangoObjectType):
class Meta:
# This type will transform all the UserModel fields
# into Graphene fields automatically
model = UserModel
# An extra field in the User Type
full_name = graphene.String()
class Query(graphene.ObjectType):
users = graphene.List(User)
def resolve_full_name(self, args, context, info):
return "{} {}".format(self.name, self.last_name)
@graphene.resolve_only_args
def resolve_users(self):
return UserModel.objects.all()
schema = graphene.Schema(query=QueryRoot)
```
If you want to learn even more, you can also check the following [examples](examples/):
Then you can simply query the schema:
```python
query = '''
query {
users {
name,
lastName
}
}
'''
result = schema.execute(query)
```
To learn more check out the following [examples](examples/):
* **Schema with Filtering**: [Cookbook example](examples/cookbook)
* **Relay Schema**: [Starwars Relay example](examples/starwars)

View File

@ -1,4 +1,6 @@
import sys, os
import sys
import os
ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, ROOT_PATH + '/examples/')

View File

@ -1,5 +1,5 @@
from cookbook.ingredients.models import Category, Ingredient
from graphene import ObjectType, Field, AbstractType, Node
from graphene import AbstractType, Field, Node
from graphene_django.filter import DjangoFilterConnectionField
from graphene_django.types import DjangoObjectType

View File

@ -1,8 +1,10 @@
import graphene
import cookbook.ingredients.schema
import graphene
# print cookbook.ingredients.schema.Query._meta.graphql_type.get_fields()['allIngredients'].args
class Query(cookbook.ingredients.schema.Query, graphene.ObjectType):
pass

View File

@ -1,14 +1,12 @@
import graphene
from graphene import relay, resolve_only_args, Schema
from graphene import Schema, relay, resolve_only_args
from graphene_django import DjangoObjectType
from .data import (create_ship, get_empire, get_faction, get_rebels, get_ship,
get_ships)
from .models import (
Character as CharacterModel,
Faction as FactionModel,
Ship as ShipModel
)
from .models import Character as CharacterModel
from .models import Faction as FactionModel
from .models import Ship as ShipModel
class Ship(DjangoObjectType):

View File

@ -1,16 +1,17 @@
from django.db import models
from django.utils.encoding import force_text
from graphene import Enum, List, ID, Boolean, Float, Int, String, Field, NonNull, Field, Dynamic
from graphene.types.json import JSONString
from graphene.types.datetime import DateTime
from graphene.utils.str_converters import to_const
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.json import JSONString
from graphene.utils.str_converters import to_const
from .compat import (ArrayField, HStoreField, JSONField, RangeField,
RelatedObject, UUIDField)
from .utils import get_related_model, import_single_dispatch
from .fields import get_connection_field
from .utils import get_related_model, import_single_dispatch
singledispatch = import_single_dispatch()
@ -37,9 +38,10 @@ def convert_django_field_with_choices(field, registry=None):
name = '{}{}'.format(meta.object_name, field.name.capitalize())
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}
named_choices_descriptions = {c[0]: c[2] for c in choices}
class EnumWithDescriptionsType(object):
@property
def description(self):
return named_choices_descriptions[self.name]

View File

@ -1,6 +1,7 @@
from promise import Promise
from django.db import connections
from promise import Promise
from .sql.tracking import unwrap_cursor, wrap_cursor
from .types import DjangoDebug

View File

@ -1,4 +1,5 @@
from graphene import ObjectType, List
from graphene import List, ObjectType
from .sql.types import DjangoDebugSQL

View File

@ -1,9 +1,11 @@
from functools import partial
from django.db.models.query import QuerySet
from graphene.relay import ConnectionField, PageInfo
from graphql_relay.connection.arrayconnection import connection_from_list_slice
from .utils import maybe_queryset, DJANGO_FILTER_INSTALLED
from .utils import DJANGO_FILTER_INSTALLED, maybe_queryset
class DjangoConnectionField(ConnectionField):

View File

@ -1,4 +1,5 @@
from functools import partial
from ..fields import DjangoConnectionField
from .utils import get_filtering_args_from_filterset, get_filterset_class

View File

@ -5,9 +5,10 @@ from django.utils.text import capfirst
from django_filters import Filter, MultipleChoiceFilter
from django_filters.filterset import FilterSet, FilterSetMetaclass
from ..forms import GlobalIDFormField, GlobalIDMultipleChoiceField
from graphql_relay.node.node import from_global_id
from ..forms import GlobalIDFormField, GlobalIDMultipleChoiceField
class GlobalIDFilter(Filter):
field_class = GlobalIDFormField

View File

@ -2,7 +2,7 @@ from datetime import datetime
import pytest
from graphene import ObjectType, Schema, Field
from graphene import Field, ObjectType, Schema
from graphene.relay import Node
from graphene_django import DjangoObjectType
from graphene_django.forms import (GlobalIDFormField,

View File

@ -1,6 +1,7 @@
import six
from graphene import Argument, String
from graphene import String
from .filterset import custom_filterset_factory, setup_filterset

View File

@ -1,7 +1,8 @@
from django import forms
from django.forms.fields import BaseTemporalField
from graphene import ID, Boolean, Float, Int, String, List
from graphene import ID, Boolean, Float, Int, List, String
from .forms import GlobalIDFormField, GlobalIDMultipleChoiceField
from .utils import import_single_dispatch

View File

@ -67,6 +67,6 @@ class Command(CommandArguments):
self.save_file(out, schema_dict)
style = getattr(self, 'style', None)
SUCCESS = getattr(style, 'SUCCESS', lambda x: x)
success = getattr(style, 'SUCCESS', lambda x: x)
self.stdout.write(SUCCESS('Successfully dumped GraphQL schema to %s' % out))
self.stdout.write(success('Successfully dumped GraphQL schema to %s' % out))

View File

@ -1,13 +1,18 @@
class Registry(object):
def __init__(self):
self._registry = {}
self._registry_models = {}
def register(self, cls):
from .types import DjangoObjectType
assert issubclass(cls, DjangoObjectType), 'Only DjangoObjectTypes can be registered, received "{}"'.format(cls.__name__)
assert issubclass(
cls, DjangoObjectType), 'Only DjangoObjectTypes can be registered, received "{}"'.format(
cls.__name__)
assert cls._meta.registry == self, 'Registry for a Model have to match.'
# assert self.get_type_for_model(cls._meta.model) == cls, 'Multiple DjangoObjectTypes registered for "{}"'.format(cls._meta.model)
# assert self.get_type_for_model(cls._meta.model) == cls, (
# 'Multiple DjangoObjectTypes registered for "{}"'.format(cls._meta.model)
# )
self._registry[cls._meta.model] = cls
def get_type_for_model(self, model):

View File

@ -1,7 +1,7 @@
import graphene
from graphene import Schema, relay
from ..types import DjangoObjectType
from ..types import DjangoObjectType
from .models import Article, Reporter

View File

@ -4,17 +4,20 @@ from django.utils.translation import ugettext_lazy as _
from py.test import raises
import graphene
from graphene.relay import Node, ConnectionField
from graphene.relay import ConnectionField, Node
from graphene.types.datetime import DateTime
from graphene.types.json import JSONString
# from graphene.core.types.custom_scalars import DateTime, JSONString
from ..compat import (ArrayField, HStoreField, JSONField, MissingType,
RangeField)
from ..converter import convert_django_field, convert_django_field_with_choices
from ..registry import Registry
from .models import Article, Reporter, Film, FilmDetails, Pet
from ..types import DjangoObjectType
from .models import Article, Film, FilmDetails, Reporter
# from graphene.core.types.custom_scalars import DateTime, JSONString
def assert_conversion(django_field, graphene_field, *args, **kwargs):
@ -166,6 +169,7 @@ def test_should_manytomany_convert_connectionorlist():
def test_should_manytomany_convert_connectionorlist_list():
class A(DjangoObjectType):
class Meta:
model = Reporter
@ -179,6 +183,7 @@ def test_should_manytomany_convert_connectionorlist_list():
def test_should_manytomany_convert_connectionorlist_connection():
class A(DjangoObjectType):
class Meta:
model = Reporter
interfaces = (Node, )
@ -196,6 +201,7 @@ def test_should_manytoone_convert_connectionorlist():
getattr(Reporter.articles, 'related')
class A(DjangoObjectType):
class Meta:
model = Article
@ -213,6 +219,7 @@ def test_should_onetoone_reverse_convert_model():
getattr(Film.details, 'related')
class A(DjangoObjectType):
class Meta:
model = FilmDetails

View File

@ -2,9 +2,9 @@ from django import forms
from py.test import raises
import graphene
from ..form_converter import convert_form_field
from graphene import ID, List, NonNull
from ..form_converter import convert_form_field
from .models import Reporter

View File

@ -8,9 +8,8 @@ import graphene
from graphene.relay import Node
from ..compat import MissingType, RangeField
from ..types import DjangoObjectType
from ..fields import DjangoConnectionField
from ..registry import reset_global_registry, get_global_registry
from ..types import DjangoObjectType
from .models import Article, Reporter
pytestmark = pytest.mark.django_db

View File

@ -1,8 +1,7 @@
from py.test import raises
from ..types import DjangoObjectType
from ..registry import Registry
from ..types import DjangoObjectType
from .models import Reporter
@ -24,10 +23,20 @@ def test_should_raise_if_model_is_invalid():
def test_should_map_fields_correctly():
class ReporterType2(DjangoObjectType):
class Meta:
model = Reporter
registry = Registry()
assert list(ReporterType2._meta.fields.keys()) == ['id', 'first_name', 'last_name', 'email', 'pets', 'a_choice', 'articles', 'films']
assert list(
ReporterType2._meta.fields.keys()) == [
'id',
'first_name',
'last_name',
'email',
'pets',
'a_choice',
'articles',
'films']
def test_should_map_only_few_fields():

View File

@ -1,12 +1,12 @@
from graphql.type import GraphQLObjectType
from mock import patch
from graphene import ObjectType, Field, Int, ID, Schema, Interface
from graphene.relay import Node, ConnectionField
from ..types import DjangoObjectType
from graphene import Interface, ObjectType, Schema
from graphene.relay import Node
from .models import Article as ArticleModel, Reporter as ReporterModel
from ..registry import reset_global_registry, Registry
from ..registry import reset_global_registry
from ..types import DjangoObjectType
from .models import Article as ArticleModel
from .models import Reporter as ReporterModel
reset_global_registry()

View File

@ -2,14 +2,16 @@ from collections import OrderedDict
import six
from graphene import ObjectType, Field
from graphene import Field, ObjectType
from graphene.types.objecttype import ObjectTypeMeta
from .converter import convert_django_field_with_choices
from graphene.types.options import Options
from .utils import get_model_fields, is_valid_django_model, DJANGO_FILTER_INSTALLED
from .registry import Registry, get_global_registry
from graphene.types.utils import merge, yank_fields_from_attrs
from graphene.utils.is_base_type import is_base_type
from graphene.types.utils import yank_fields_from_attrs, merge
from .converter import convert_django_field_with_choices
from .registry import Registry, get_global_registry
from .utils import (DJANGO_FILTER_INSTALLED, get_model_fields,
is_valid_django_model)
def construct_fields(options):
@ -95,6 +97,7 @@ class DjangoObjectTypeMeta(ObjectTypeMeta):
class DjangoObjectType(six.with_metaclass(DjangoObjectTypeMeta, ObjectType)):
@classmethod
def is_type_of(cls, root, context, info):
if isinstance(root, cls):

View File

@ -1,12 +1,17 @@
import inspect
from django.db import models
from django.db.models.manager import Manager
from .compat import RelatedObject
# from graphene.utils import LazyList
class LazyList(object):
pass
from .compat import RelatedObject
try:
import django_filters # noqa

View File

@ -2,6 +2,7 @@ from graphql_django_view import GraphQLView as BaseGraphQLView
class GraphQLView(BaseGraphQLView):
def __init__(self, schema, **kwargs):
super(GraphQLView, self).__init__(
schema=schema,

View File

@ -1,2 +1,12 @@
[tool:pytest]
DJANGO_SETTINGS_MODULE = django_test_settings
[flake8]
exclude = setup.py,docs/*,examples/*,tests,graphene_django/debug/sql/*
max-line-length = 120
[coverage:run]
omit = */tests/*
[isort]
known_first_party=graphene,graphene_django