Merge branch 'main' into chore/pre-commit

This commit is contained in:
Nikolai R Kristiansen 2022-09-25 17:16:00 +02:00
commit 8fb310a900
11 changed files with 78 additions and 35 deletions

View File

@ -151,7 +151,7 @@ For example the following ``Model`` and ``DjangoObjectType``:
Results in the following GraphQL schema definition:
.. code::
.. code:: graphql
type Pet {
id: ID!
@ -178,7 +178,7 @@ You can disable this automatic conversion by setting
fields = ("id", "kind",)
convert_choices_to_enum = False
.. code::
.. code:: graphql
type Pet {
id: ID!
@ -313,7 +313,7 @@ Additionally, Resolvers will receive **any arguments declared in the field defin
bar=graphene.Int()
)
def resolve_question(root, info, foo, bar):
def resolve_question(root, info, foo=None, bar=None):
# If `foo` or `bar` are declared in the GraphQL query they will be here, else None.
return Question.objects.filter(foo=foo, bar=bar).first()
@ -336,12 +336,12 @@ of Django's ``HTTPRequest`` in your resolve methods, such as checking for authen
class Query(graphene.ObjectType):
questions = graphene.List(QuestionType)
def resolve_questions(root, info):
# See if a user is authenticated
if info.context.user.is_authenticated():
return Question.objects.all()
else:
return Question.objects.none()
def resolve_questions(root, info):
# See if a user is authenticated
if info.context.user.is_authenticated():
return Question.objects.all()
else:
return Question.objects.none()
DjangoObjectTypes
@ -418,29 +418,29 @@ the core graphene pages for more information on customizing the Relay experience
You can now execute queries like:
.. code:: python
.. code:: graphql
{
questions (first: 2, after: "YXJyYXljb25uZWN0aW9uOjEwNQ==") {
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
startCursor
endCursor
hasNextPage
hasPreviousPage
}
edges {
cursor
node {
id
question_text
}
cursor
node {
id
question_text
}
}
}
}
Which returns:
.. code:: python
.. code:: json
{
"data": {

View File

@ -207,3 +207,22 @@ Default: ``True``
GRAPHENE = {
'GRAPHIQL_HEADER_EDITOR_ENABLED': True,
}
``GRAPHIQL_SHOULD_PERSIST_HEADERS``
---------------------
Set to ``True`` if you want to persist GraphiQL headers after refreshing the page.
This setting is passed to ``shouldPersistHeaders`` GraphiQL options, for details refer to GraphiQLDocs_.
.. _GraphiQLDocs: https://github.com/graphql/graphiql/tree/main/packages/graphiql#options
Default: ``False``
.. code:: python
GRAPHENE = {
'GRAPHIQL_SHOULD_PERSIST_HEADERS': False,
}

View File

@ -35,6 +35,7 @@ Now sync your database for the first time:
.. code:: bash
cd ..
python manage.py migrate
Let's create a few simple models...
@ -77,6 +78,18 @@ Add ingredients as INSTALLED_APPS:
"cookbook.ingredients",
]
Make sure the app name in ``cookbook.ingredients.apps.IngredientsConfig`` is set to ``cookbook.ingredients``.
.. code:: python
# cookbook/ingredients/apps.py
from django.apps import AppConfig
class IngredientsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'cookbook.ingredients'
Don't forget to create & run migrations:

View File

@ -2,7 +2,7 @@ from functools import partial
from django.db.models.query import QuerySet
from graphql_relay.connection.array_connection import (
from graphql_relay import (
connection_from_array_slice,
cursor_to_offset,
get_offset_with_default,

View File

@ -41,6 +41,7 @@ DEFAULTS = {
# This sets headerEditorEnabled GraphiQL option, for details go to
# https://github.com/graphql/graphiql/tree/main/packages/graphiql#options
"GRAPHIQL_HEADER_EDITOR_ENABLED": True,
"GRAPHIQL_SHOULD_PERSIST_HEADERS": False,
"ATOMIC_MUTATIONS": False,
}

View File

@ -10,14 +10,6 @@
history,
location,
) {
// Parse the cookie value for a CSRF token
var csrftoken;
var cookies = ("; " + document.cookie).split("; csrftoken=");
if (cookies.length == 2) {
csrftoken = cookies.pop().split(";").shift();
} else {
csrftoken = document.querySelector("[name=csrfmiddlewaretoken]").value;
}
// Collect the URL parameters
var parameters = {};
@ -68,9 +60,19 @@
var headers = opts.headers || {};
headers['Accept'] = headers['Accept'] || 'application/json';
headers['Content-Type'] = headers['Content-Type'] || 'application/json';
// Parse the cookie value for a CSRF token
var csrftoken;
var cookies = ("; " + document.cookie).split("; csrftoken=");
if (cookies.length == 2) {
csrftoken = cookies.pop().split(";").shift();
} else {
csrftoken = document.querySelector("[name=csrfmiddlewaretoken]").value;
}
if (csrftoken) {
headers['X-CSRFToken'] = csrftoken
}
return fetch(fetchURL, {
method: "post",
headers: headers,
@ -176,6 +178,7 @@
onEditVariables: onEditVariables,
onEditOperationName: onEditOperationName,
headerEditorEnabled: GRAPHENE_SETTINGS.graphiqlHeaderEditorEnabled,
shouldPersistHeaders: GRAPHENE_SETTINGS.graphiqlShouldPersistHeaders,
query: parameters.query,
};
if (parameters.variables) {

View File

@ -46,6 +46,7 @@ add "&raw" to the end of the URL within a browser.
subscriptionPath: "{{subscription_path}}",
{% endif %}
graphiqlHeaderEditorEnabled: {{ graphiql_header_editor_enabled|yesno:"true,false" }},
graphiqlShouldPersistHeaders: {{ graphiql_should_persist_headers|yesno:"true,false" }},
};
</script>
<script src="{% static 'graphene_django/graphiql.js' %}"></script>

View File

@ -114,7 +114,9 @@ class TestShouldCallGetQuerySetOnForeignKey:
"""
result = self.schema.execute(
query, variables={"id": self.reporter.id}, context_value={"admin": True},
query,
variables={"id": self.reporter.id},
context_value={"admin": True},
)
assert not result.errors
assert result.data == {"reporter": {"firstName": "Jane"}}
@ -149,7 +151,9 @@ class TestShouldCallGetQuerySetOnForeignKey:
"""
result = self.schema.execute(
query, variables={"id": self.articles[0].id}, context_value={"admin": True},
query,
variables={"id": self.articles[0].id},
context_value={"admin": True},
)
assert not result.errors
assert result.data["article"] == {
@ -170,7 +174,9 @@ class TestShouldCallGetQuerySetOnForeignKey:
"""
result = self.schema.execute(
query, variables={"id": self.reporter.id}, context_value={"admin": True},
query,
variables={"id": self.reporter.id},
context_value={"admin": True},
)
assert not result.errors
assert result.data["reporter"] == {

View File

@ -122,7 +122,7 @@ def validate_fields(type_, model, fields, only_fields, exclude_fields):
class DjangoObjectTypeOptions(ObjectTypeOptions):
model = None # type: Model
model = None # type: Type[Model]
registry = None # type: Registry
connection = None # type: Type[Connection]

View File

@ -162,6 +162,7 @@ class GraphQLView(View):
subscription_path=self.subscription_path,
# GraphiQL headers tab,
graphiql_header_editor_enabled=graphene_settings.GRAPHIQL_HEADER_EDITOR_ENABLED,
graphiql_should_persist_headers=graphene_settings.GRAPHIQL_SHOULD_PERSIST_HEADERS,
)
if self.batch:

View File

@ -59,8 +59,7 @@ setup(
keywords="api graphql protocol rest relay graphene",
packages=find_packages(exclude=["tests", "examples", "examples.*"]),
install_requires=[
# "graphene>=3.0,<4",
"graphene @ git+https://github.com/loft-orbital/graphene.git@loft-v3-1.0#egg=graphene",
"graphene>=3.0,<4",
"graphql-core>=3.1.0,<4",
"graphql-relay>=3.1.1,<4",
"Django>=3.2",