Skip to content

Commit 9840a64

Browse files
authored
Merge branch 'master' into master
2 parents 701611c + f045147 commit 9840a64

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1299
-207
lines changed

.travis.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ install:
1111
pip install -e .[test]
1212
pip install psycopg2 # Required for Django postgres fields testing
1313
pip install django==$DJANGO_VERSION
14-
if [ $DJANGO_VERSION = 1.8 ]; then # DRF dropped 1.8 support at 3.7.0
14+
if (($(echo "$DJANGO_VERSION <= 1.9" | bc -l))); then # DRF dropped 1.8 and 1.9 support at 3.7.0
1515
pip install djangorestframework==3.6.4
1616
fi
1717
python setup.py develop
@@ -38,6 +38,12 @@ env:
3838
matrix:
3939
fast_finish: true
4040
include:
41+
- python: '3.4'
42+
env: TEST_TYPE=build DJANGO_VERSION=2.0
43+
- python: '3.5'
44+
env: TEST_TYPE=build DJANGO_VERSION=2.0
45+
- python: '3.6'
46+
env: TEST_TYPE=build DJANGO_VERSION=2.0
4147
- python: '2.7'
4248
env: TEST_TYPE=build DJANGO_VERSION=1.8
4349
- python: '2.7'

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
The MIT License (MIT)
2+
3+
Copyright (c) 2016-Present Syrus Akbary
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

MANIFEST.in

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
include README.md
1+
include README.md LICENSE
22
recursive-include graphene_django/templates *

docs/authorization.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ define a resolve method for that field and return the desired queryset.
6161
from .models import Post
6262
6363
class Query(ObjectType):
64-
all_posts = DjangoFilterConnectionField(CategoryNode)
64+
all_posts = DjangoFilterConnectionField(PostNode)
6565
6666
def resolve_all_posts(self, args, info):
6767
return Post.objects.filter(published=True)
@@ -79,7 +79,7 @@ with the context argument.
7979
from .models import Post
8080
8181
class Query(ObjectType):
82-
my_posts = DjangoFilterConnectionField(CategoryNode)
82+
my_posts = DjangoFilterConnectionField(PostNode)
8383
8484
def resolve_my_posts(self, info):
8585
# context will reference to the Django request

docs/filtering.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,4 +145,4 @@ pre-filter animals owned by the authenticated user (set in ``context.user``).
145145
@property
146146
def qs(self):
147147
# The query context can be found in self.request.
148-
return super(AnimalFilter, self).filter(owner=self.request.user)
148+
return super(AnimalFilter, self).qs.filter(owner=self.request.user)

docs/form-mutations.rst

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
Integration with Django forms
2+
=============================
3+
4+
Graphene-Django comes with mutation classes that will convert the fields on Django forms into inputs on a mutation.
5+
*Note: the API is experimental and will likely change in the future.*
6+
7+
FormMutation
8+
------------
9+
10+
.. code:: python
11+
12+
class MyForm(forms.Form):
13+
name = forms.CharField()
14+
15+
class MyMutation(FormMutation):
16+
class Meta:
17+
form_class = MyForm
18+
19+
``MyMutation`` will automatically receive an ``input`` argument. This argument should be a ``dict`` where the key is ``name`` and the value is a string.
20+
21+
ModelFormMutation
22+
-----------------
23+
24+
``ModelFormMutation`` will pull the fields from a ``ModelForm``.
25+
26+
.. code:: python
27+
28+
class Pet(models.Model):
29+
name = models.CharField()
30+
31+
class PetForm(forms.ModelForm):
32+
class Meta:
33+
model = Pet
34+
fields = ('name',)
35+
36+
# This will get returned when the mutation completes successfully
37+
class PetType(DjangoObjectType):
38+
class Meta:
39+
model = Pet
40+
41+
class PetMutation(DjangoModelFormMutation):
42+
class Meta:
43+
form_class = PetForm
44+
45+
``PetMutation`` will grab the fields from ``PetForm`` and turn them into inputs. If the form is valid then the mutation
46+
will lookup the ``DjangoObjectType`` for the ``Pet`` model and return that under the key ``pet``. Otherwise it will
47+
return a list of errors.
48+
49+
You can change the input name (default is ``input``) and the return field name (default is the model name lowercase).
50+
51+
.. code:: python
52+
53+
class PetMutation(DjangoModelFormMutation):
54+
class Meta:
55+
form_class = PetForm
56+
input_field_name = 'data'
57+
return_field_name = 'my_pet'
58+
59+
Form validation
60+
---------------
61+
62+
Form mutations will call ``is_valid()`` on your forms.
63+
64+
If the form is valid then ``form_valid(form, info)`` is called on the mutation. Override this method to change how
65+
the form is saved or to return a different Graphene object type.
66+
67+
If the form is *not* valid then a list of errors will be returned. These errors have two fields: ``field``, a string
68+
containing the name of the invalid form field, and ``messages``, a list of strings with the validation messages.

docs/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Contents:
1212
authorization
1313
debug
1414
rest-framework
15+
form-mutations
1516
introspection

docs/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
sphinx
22
# Docs template
3-
https://github.com/graphql-python/graphene-python.org/archive/docs.zip
3+
http://graphene-python.org/sphinx_graphene_theme.zip

docs/rest-framework.rst

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,46 @@ You can create a Mutation based on a serializer by using the
1919
class Meta:
2020
serializer_class = MySerializer
2121
22+
Create/Update Operations
23+
---------------------
24+
25+
By default ModelSerializers accept create and update operations. To
26+
customize this use the `model_operations` attribute. The update
27+
operation looks up models by the primary key by default. You can
28+
customize the look up with the lookup attribute.
29+
30+
.. code:: python
31+
32+
from graphene_django.rest_framework.mutation import SerializerMutation
33+
34+
class AwesomeModelMutation(SerializerMutation):
35+
class Meta:
36+
serializer_class = MyModelSerializer
37+
model_operations = ['create', 'update']
38+
lookup_field = 'id'
39+
40+
Overriding Update Queries
41+
-------------------------
42+
43+
Use the method `get_serializer_kwargs` to override how
44+
updates are applied.
45+
46+
.. code:: python
47+
48+
from graphene_django.rest_framework.mutation import SerializerMutation
49+
50+
class AwesomeModelMutation(SerializerMutation):
51+
class Meta:
52+
serializer_class = MyModelSerializer
53+
54+
@classmethod
55+
def get_serializer_kwargs(cls, root, info, **input):
56+
if 'id' in input:
57+
instance = Post.objects.filter(id=input['id'], owner=info.context.user).first()
58+
if instance:
59+
return {'instance': instance, 'data': input, 'partial': True}
60+
61+
else:
62+
raise http.Http404
63+
64+
return {'data': input, 'partial': True}

docs/tutorial-relay.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Create ``cookbook/ingredients/schema.py`` and type the following:
118118
.. code:: python
119119
120120
# cookbook/ingredients/schema.py
121-
from graphene import relay, ObjectType, AbstractType
121+
from graphene import relay, ObjectType
122122
from graphene_django import DjangoObjectType
123123
from graphene_django.filter import DjangoFilterConnectionField
124124
@@ -147,7 +147,7 @@ Create ``cookbook/ingredients/schema.py`` and type the following:
147147
interfaces = (relay.Node, )
148148
149149
150-
class Query(AbstractType):
150+
class Query(object):
151151
category = relay.Node.Field(CategoryNode)
152152
all_categories = DjangoFilterConnectionField(CategoryNode)
153153

0 commit comments

Comments
 (0)