mirror of
https://github.com/graphql-python/graphene.git
synced 2024-11-27 03:53:56 +03:00
Merge branch 'master' into django-choices-grouping
# Conflicts: # graphene/contrib/django/tests/test_converter.py
This commit is contained in:
commit
4636f9290a
|
@ -362,6 +362,12 @@ $title
|
||||||
.docs
|
.docs
|
||||||
@extend $wrapper
|
@extend $wrapper
|
||||||
|
|
||||||
|
.homepage-intro
|
||||||
|
col(1/2)
|
||||||
|
|
||||||
|
.homepage-schema
|
||||||
|
col(1/2)
|
||||||
|
|
||||||
.docs-aside
|
.docs-aside
|
||||||
col(1/4)
|
col(1/4)
|
||||||
margin-top 60px
|
margin-top 60px
|
||||||
|
|
|
@ -10,8 +10,8 @@ Let's build a basic GraphQL schema from scratch.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Python (2.6.5+, 2.7, 3.2, 3.3, 3.4, 3.5, pypy)
|
- Python (2.7, 3.2, 3.3, 3.4, 3.5, pypy)
|
||||||
- Graphene (0.4+)
|
- Graphene (0.10+)
|
||||||
|
|
||||||
|
|
||||||
## Project setup
|
## Project setup
|
||||||
|
|
|
@ -3,8 +3,50 @@ path: /
|
||||||
---
|
---
|
||||||
<div class="starwars-example-wrapper"><a class="starwars-example" href="http://swapi.graphene-python.org/">Check our Django Starwars API example!</a></div>
|
<div class="starwars-example-wrapper"><a class="starwars-example" href="http://swapi.graphene-python.org/">Check our Django Starwars API example!</a></div>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<div class="homepage-intro">
|
||||||
|
|
||||||
## Meet Graphene
|
## Meet Graphene
|
||||||
|
|
||||||
Graphene is a Python library for building GraphQL schemas/types fast and easily.
|
Graphene is a Python library for building *GraphQL* schemas/types fast and easily.
|
||||||
|
|
||||||
**But, what is GraphQL?** A GraphQL query is a string interpreted by a server that returns data in a specified format. We believe *GraphQL* is the next big thing after peanut butter and *REST*.
|
|
||||||
|
* **Easy to use**: Graphene helps you use *GraphQL* in Python easily.
|
||||||
|
* Graphene has **builtin support for Relay**.
|
||||||
|
* Support for **Django**, **SQLAlchemy** and **GAE**: mapping the models automatically to *GraphQL* types.
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="homepage-schema">
|
||||||
|
|
||||||
|
```python
|
||||||
|
import graphene
|
||||||
|
|
||||||
|
class Query(graphene.ObjectType):
|
||||||
|
hello = graphene.String()
|
||||||
|
|
||||||
|
def resolve_hello(self, args, info):
|
||||||
|
return 'world'
|
||||||
|
|
||||||
|
schema = graphene.Schema(query=Query)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```python
|
||||||
|
result = schema.execute('{ hello }')
|
||||||
|
```
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
#### What is GraphQL?
|
||||||
|
*GraphQL* is a data query language and runtime designed to request and deliver data in a performant way.
|
||||||
|
|
||||||
|
Advantages of using *GraphQL*:
|
||||||
|
* Only **one API endpoint**. One roundtrip for fetch everything you need.
|
||||||
|
* No data overfetching or underfetching.
|
||||||
|
* Autogenerated Graphical UI and docs based in your schema.
|
||||||
|
<div>
|
|
@ -1,4 +1,5 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.encoding import force_text
|
||||||
|
|
||||||
from ...core.classtypes.enum import Enum
|
from ...core.classtypes.enum import Enum
|
||||||
from ...core.types.custom_scalars import DateTime, JSONString
|
from ...core.types.custom_scalars import DateTime, JSONString
|
||||||
|
@ -14,13 +15,14 @@ singledispatch = import_single_dispatch()
|
||||||
|
|
||||||
def convert_choices(choices):
|
def convert_choices(choices):
|
||||||
for value, name in choices:
|
for value, name in choices:
|
||||||
yield to_const(name), value
|
yield to_const(force_text(name)), value
|
||||||
|
|
||||||
|
|
||||||
def convert_django_field_with_choices(field):
|
def convert_django_field_with_choices(field):
|
||||||
choices = getattr(field, 'choices', None)
|
choices = getattr(field, 'choices', None)
|
||||||
if choices:
|
model = getattr(field, 'model', None)
|
||||||
meta = field.model._meta
|
if choices and model:
|
||||||
|
meta = model._meta
|
||||||
name = '{}_{}_{}'.format(meta.app_label, meta.object_name, field.name)
|
name = '{}_{}_{}'.format(meta.app_label, meta.object_name, field.name)
|
||||||
return Enum(name.upper(), list(convert_choices(choices)), description=field.help_text)
|
return Enum(name.upper(), list(convert_choices(choices)), description=field.help_text)
|
||||||
return convert_django_field(field)
|
return convert_django_field(field)
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
CHOICES = (
|
||||||
|
(1, 'this'),
|
||||||
|
(2, _('that'))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Pet(models.Model):
|
class Pet(models.Model):
|
||||||
|
@ -22,6 +28,7 @@ class Reporter(models.Model):
|
||||||
last_name = models.CharField(max_length=30)
|
last_name = models.CharField(max_length=30)
|
||||||
email = models.EmailField()
|
email = models.EmailField()
|
||||||
pets = models.ManyToManyField('self')
|
pets = models.ManyToManyField('self')
|
||||||
|
a_choice = models.CharField(max_length=30, choices=CHOICES)
|
||||||
|
|
||||||
def __str__(self): # __unicode__ on Python 2
|
def __str__(self): # __unicode__ on Python 2
|
||||||
return "%s %s" % (self.first_name, self.last_name)
|
return "%s %s" % (self.first_name, self.last_name)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import pytest
|
import pytest
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from py.test import raises
|
from py.test import raises
|
||||||
|
|
||||||
import graphene
|
import graphene
|
||||||
|
@ -125,7 +126,22 @@ def test_field_with_grouped_choices():
|
||||||
)),
|
)),
|
||||||
))
|
))
|
||||||
|
|
||||||
class TranslatedModel(models.Model):
|
class GroupedChoicesModel(models.Model):
|
||||||
|
language = field
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
app_label = 'test'
|
||||||
|
|
||||||
|
convert_django_field_with_choices(field)
|
||||||
|
|
||||||
|
|
||||||
|
def test_field_with_choices_gettext():
|
||||||
|
field = models.CharField(help_text='Language', choices=(
|
||||||
|
('es', _('Spanish')),
|
||||||
|
('en', _('English'))
|
||||||
|
))
|
||||||
|
|
||||||
|
class TranslatedChoicesModel(models.Model):
|
||||||
language = field
|
language = field
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -77,6 +77,7 @@ class Schema(object):
|
||||||
self,
|
self,
|
||||||
query=self.T(self.query),
|
query=self.T(self.query),
|
||||||
mutation=self.T(self.mutation),
|
mutation=self.T(self.mutation),
|
||||||
|
types=[self.T(_type) for _type in list(self._types_names.values())],
|
||||||
subscription=self.T(self.subscription))
|
subscription=self.T(self.subscription))
|
||||||
|
|
||||||
def register(self, object_type, force=False):
|
def register(self, object_type, force=False):
|
||||||
|
|
|
@ -132,6 +132,21 @@ def test_schema_register():
|
||||||
assert schema.get_type('MyType') == MyType
|
assert schema.get_type('MyType') == MyType
|
||||||
|
|
||||||
|
|
||||||
|
def test_schema_register_interfaces():
|
||||||
|
class Query(ObjectType):
|
||||||
|
f = Field(Character)
|
||||||
|
|
||||||
|
def resolve_f(self, args, info):
|
||||||
|
return Human()
|
||||||
|
|
||||||
|
schema = Schema(query=Query)
|
||||||
|
|
||||||
|
schema.register(Human)
|
||||||
|
|
||||||
|
result = schema.execute('{ f { name } }')
|
||||||
|
assert not result.errors
|
||||||
|
|
||||||
|
|
||||||
def test_schema_register_no_query_type():
|
def test_schema_register_no_query_type():
|
||||||
schema = Schema(name='My own schema')
|
schema = Schema(name='My own schema')
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user