mirror of
https://github.com/graphql-python/graphene-django.git
synced 2024-11-23 10:04:05 +03:00
Improved python syntax and sorts (pep8). Improved Readme
This commit is contained in:
parent
0434899b4e
commit
4e23c3ccf6
2
.coveragerc
Normal file
2
.coveragerc
Normal file
|
@ -0,0 +1,2 @@
|
|||
[run]
|
||||
omit = */tests/*,graphene_django/debug/sql/*
|
52
README.md
52
README.md
|
@ -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)
|
||||
|
|
|
@ -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/')
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
@ -40,6 +41,7 @@ def convert_django_field_with_choices(field, registry=None):
|
|||
named_choices_descriptions = {c[0]: c[2] for c in choices}
|
||||
|
||||
class EnumWithDescriptionsType(object):
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return named_choices_descriptions[self.name]
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from graphene import ObjectType, List
|
||||
from graphene import List, ObjectType
|
||||
|
||||
from .sql.types import DjangoDebugSQL
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from functools import partial
|
||||
|
||||
from ..fields import DjangoConnectionField
|
||||
from .utils import get_filtering_args_from_filterset, get_filterset_class
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import six
|
||||
|
||||
from graphene import Argument, String
|
||||
from graphene import String
|
||||
|
||||
from .filterset import custom_filterset_factory, setup_filterset
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import graphene
|
||||
from graphene import Schema, relay
|
||||
from ..types import DjangoObjectType
|
||||
|
||||
from ..types import DjangoObjectType
|
||||
from .models import Article, Reporter
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue
Block a user