From eac113e136631b37e7a0bbb6b41f2a9892648a4b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 Apr 2024 03:39:21 +0300 Subject: [PATCH 1/4] Bump django from 3.2.24 to 3.2.25 in /examples/cookbook (#1508) Bumps [django](https://github.com/django/django) from 3.2.24 to 3.2.25. - [Commits](https://github.com/django/django/compare/3.2.24...3.2.25) --- updated-dependencies: - dependency-name: django dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- examples/cookbook/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cookbook/requirements.txt b/examples/cookbook/requirements.txt index 74baf1219..758d66cea 100644 --- a/examples/cookbook/requirements.txt +++ b/examples/cookbook/requirements.txt @@ -1,5 +1,5 @@ graphene>=2.1,<3 graphene-django>=2.1,<3 graphql-core>=2.1,<3 -django==3.2.24 +django==3.2.25 django-filter>=2 From ea45de02adae1b86121692e9a004853c14b311af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Clgen=20Sar=C4=B1kavak?= Date: Tue, 9 Apr 2024 03:43:34 +0300 Subject: [PATCH 2/4] Make use of http.HTTPStatus for response status code checks (#1487) --- graphene_django/tests/test_views.py | 87 +++++++++++++++-------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/graphene_django/tests/test_views.py b/graphene_django/tests/test_views.py index c2b42bce4..2f9a1c32e 100644 --- a/graphene_django/tests/test_views.py +++ b/graphene_django/tests/test_views.py @@ -1,4 +1,5 @@ import json +from http import HTTPStatus from unittest.mock import patch import pytest @@ -37,7 +38,7 @@ def jl(**kwargs): def test_graphiql_is_enabled(client): response = client.get(url_string(), HTTP_ACCEPT="text/html") - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response["Content-Type"].split(";")[0] == "text/html" @@ -46,7 +47,7 @@ def test_qfactor_graphiql(client): url_string(query="{test}"), HTTP_ACCEPT="application/json;q=0.8, text/html;q=0.9", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response["Content-Type"].split(";")[0] == "text/html" @@ -55,7 +56,7 @@ def test_qfactor_json(client): url_string(query="{test}"), HTTP_ACCEPT="text/html;q=0.8, application/json;q=0.9", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response["Content-Type"].split(";")[0] == "application/json" assert response_json(response) == {"data": {"test": "Hello World"}} @@ -63,7 +64,7 @@ def test_qfactor_json(client): def test_allows_get_with_query_param(client): response = client.get(url_string(query="{test}")) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello World"}} @@ -75,7 +76,7 @@ def test_allows_get_with_variable_values(client): ) ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -94,7 +95,7 @@ def test_allows_get_with_operation_name(client): ) ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == { "data": {"test": "Hello World", "shared": "Hello Everyone"} } @@ -103,7 +104,7 @@ def test_allows_get_with_operation_name(client): def test_reports_validation_errors(client): response = client.get(url_string(query="{ test, unknownOne, unknownTwo }")) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [ { @@ -128,7 +129,7 @@ def test_errors_when_missing_operation_name(client): ) ) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [ { @@ -146,7 +147,7 @@ def test_errors_when_sending_a_mutation_via_get(client): """ ) ) - assert response.status_code == 405 + assert response.status_code == HTTPStatus.METHOD_NOT_ALLOWED assert response_json(response) == { "errors": [ {"message": "Can only perform a mutation operation from a POST request."} @@ -165,7 +166,7 @@ def test_errors_when_selecting_a_mutation_within_a_get(client): ) ) - assert response.status_code == 405 + assert response.status_code == HTTPStatus.METHOD_NOT_ALLOWED assert response_json(response) == { "errors": [ {"message": "Can only perform a mutation operation from a POST request."} @@ -184,14 +185,14 @@ def test_allows_mutation_to_exist_within_a_get(client): ) ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello World"}} def test_allows_post_with_json_encoding(client): response = client.post(url_string(), j(query="{test}"), "application/json") - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello World"}} @@ -200,7 +201,7 @@ def test_batch_allows_post_with_json_encoding(client): batch_url_string(), jl(id=1, query="{test}"), "application/json" ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == [ {"id": 1, "data": {"test": "Hello World"}, "status": 200} ] @@ -209,7 +210,7 @@ def test_batch_allows_post_with_json_encoding(client): def test_batch_fails_if_is_empty(client): response = client.post(batch_url_string(), "[]", "application/json") - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "Received an empty list in the batch request."}] } @@ -222,7 +223,7 @@ def test_allows_sending_a_mutation_via_post(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"writeTest": {"test": "Hello World"}}} @@ -233,7 +234,7 @@ def test_allows_post_with_url_encoding(client): "application/x-www-form-urlencoded", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello World"}} @@ -247,7 +248,7 @@ def test_supports_post_json_query_with_string_variables(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -262,7 +263,7 @@ def test_batch_supports_post_json_query_with_string_variables(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == [ {"id": 1, "data": {"test": "Hello Dolly"}, "status": 200} ] @@ -278,7 +279,7 @@ def test_supports_post_json_query_with_json_variables(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -293,7 +294,7 @@ def test_batch_supports_post_json_query_with_json_variables(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == [ {"id": 1, "data": {"test": "Hello Dolly"}, "status": 200} ] @@ -311,7 +312,7 @@ def test_supports_post_url_encoded_query_with_string_variables(client): "application/x-www-form-urlencoded", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -322,7 +323,7 @@ def test_supports_post_json_quey_with_get_variable_values(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -333,7 +334,7 @@ def test_post_url_encoded_query_with_get_variable_values(client): "application/x-www-form-urlencoded", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -344,7 +345,7 @@ def test_supports_post_raw_text_query_with_get_variable_values(client): "application/graphql", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"test": "Hello Dolly"}} @@ -365,7 +366,7 @@ def test_allows_post_with_operation_name(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == { "data": {"test": "Hello World", "shared": "Hello Everyone"} } @@ -389,7 +390,7 @@ def test_batch_allows_post_with_operation_name(client): "application/json", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == [ { "id": 1, @@ -413,7 +414,7 @@ def test_allows_post_with_get_operation_name(client): "application/graphql", ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == { "data": {"test": "Hello World", "shared": "Hello Everyone"} } @@ -430,7 +431,7 @@ def test_inherited_class_with_attributes_works(client): # Check graphiql works response = client.get(url_string(inherited_url), HTTP_ACCEPT="text/html") - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK @pytest.mark.urls("graphene_django.tests.urls_pretty") @@ -452,7 +453,7 @@ def test_supports_pretty_printing_by_request(client): def test_handles_field_errors_caught_by_graphql(client): response = client.get(url_string(query="{thrower}")) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == { "data": None, "errors": [ @@ -467,7 +468,7 @@ def test_handles_field_errors_caught_by_graphql(client): def test_handles_syntax_errors_caught_by_graphql(client): response = client.get(url_string(query="syntaxerror")) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [ { @@ -481,7 +482,7 @@ def test_handles_syntax_errors_caught_by_graphql(client): def test_handles_errors_caused_by_a_lack_of_query(client): response = client.get(url_string()) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "Must provide query string."}] } @@ -490,7 +491,7 @@ def test_handles_errors_caused_by_a_lack_of_query(client): def test_handles_not_expected_json_bodies(client): response = client.post(url_string(), "[]", "application/json") - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "The received data is not a valid JSON query."}] } @@ -499,7 +500,7 @@ def test_handles_not_expected_json_bodies(client): def test_handles_invalid_json_bodies(client): response = client.post(url_string(), "[oh}", "application/json") - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "POST body sent invalid JSON."}] } @@ -514,14 +515,14 @@ def mocked_read(*args): valid_json = json.dumps({"foo": "bar"}) response = client.post(url_string(), valid_json, "application/json") - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == {"errors": [{"message": "foo-bar"}]} def test_handles_incomplete_json_bodies(client): response = client.post(url_string(), '{"query":', "application/json") - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "POST body sent invalid JSON."}] } @@ -533,7 +534,7 @@ def test_handles_plain_post_text(client): "query helloWho($who: String){ test(who: $who) }", "text/plain", ) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "Must provide query string."}] } @@ -545,7 +546,7 @@ def test_handles_poorly_formed_variables(client): query="query helloWho($who: String){ test(who: $who) }", variables="who:You" ) ) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST assert response_json(response) == { "errors": [{"message": "Variables are invalid JSON."}] } @@ -553,7 +554,7 @@ def test_handles_poorly_formed_variables(client): def test_handles_unsupported_http_methods(client): response = client.put(url_string(query="{test}")) - assert response.status_code == 405 + assert response.status_code == HTTPStatus.METHOD_NOT_ALLOWED assert response["Allow"] == "GET, POST" assert response_json(response) == { "errors": [{"message": "GraphQL only supports GET and POST requests."}] @@ -563,7 +564,7 @@ def test_handles_unsupported_http_methods(client): def test_passes_request_into_context_request(client): response = client.get(url_string(query="{request}", q="testing")) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == {"data": {"request": "testing"}} @@ -857,7 +858,7 @@ def test_allow_introspection(client): response = client.post( url_string("/graphql/", query="{__schema {queryType {name}}}") ) - assert response.status_code == 200 + assert response.status_code == HTTPStatus.OK assert response_json(response) == { "data": {"__schema": {"queryType": {"name": "QueryRoot"}}} @@ -869,7 +870,7 @@ def test_allow_introspection(client): def test_validation_disallow_introspection(client, url): response = client.post(url_string(url, query="{__schema {queryType {name}}}")) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST json_response = response_json(response) assert "data" not in json_response @@ -888,7 +889,7 @@ def test_validation_disallow_introspection(client, url): def test_within_max_validation_errors(client, url): response = client.post(url_string(url, query=QUERY_WITH_TWO_INTROSPECTIONS)) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST json_response = response_json(response) assert "data" not in json_response @@ -913,7 +914,7 @@ def test_within_max_validation_errors(client, url): def test_exceeds_max_validation_errors(client, url): response = client.post(url_string(url, query=QUERY_WITH_TWO_INTROSPECTIONS)) - assert response.status_code == 400 + assert response.status_code == HTTPStatus.BAD_REQUEST json_response = response_json(response) assert "data" not in json_response From 6f21dc7a9447721c6542f8ebc8fd60a510289566 Mon Sep 17 00:00:00 2001 From: Kien Dang Date: Thu, 18 Apr 2024 12:00:31 +0800 Subject: [PATCH 3/4] Not require explicitly set `ordering` in `DjangoConnectionField` (#1518) * Revert "feat!: check django model has a default ordering when used in a relay connection (#1495)" This reverts commit 96c09ac439985d9548678a08221e86056ec1e703. * Fix assert no warning for pytest>=8 --- examples/starwars/models.py | 3 -- graphene_django/fields.py | 8 +----- graphene_django/filter/tests/conftest.py | 3 -- graphene_django/tests/models.py | 12 -------- graphene_django/tests/test_fields.py | 36 ++---------------------- 5 files changed, 3 insertions(+), 59 deletions(-) diff --git a/examples/starwars/models.py b/examples/starwars/models.py index c49206a4f..fb76b0395 100644 --- a/examples/starwars/models.py +++ b/examples/starwars/models.py @@ -24,9 +24,6 @@ def __str__(self): class Ship(models.Model): - class Meta: - ordering = ["pk"] - name = models.CharField(max_length=50) faction = models.ForeignKey(Faction, on_delete=models.CASCADE, related_name="ships") diff --git a/graphene_django/fields.py b/graphene_django/fields.py index a1b9a2ccb..1bbe1f3d2 100644 --- a/graphene_django/fields.py +++ b/graphene_django/fields.py @@ -101,19 +101,13 @@ def type(self): non_null = True assert issubclass( _type, DjangoObjectType - ), "DjangoConnectionField only accepts DjangoObjectType types as underlying type" + ), "DjangoConnectionField only accepts DjangoObjectType types" assert _type._meta.connection, "The type {} doesn't have a connection".format( _type.__name__ ) connection_type = _type._meta.connection if non_null: return NonNull(connection_type) - # Since Relay Connections require to have a predictible ordering for pagination, - # check on init that the Django model provided has a default ordering declared. - model = connection_type._meta.node._meta.model - assert ( - len(getattr(model._meta, "ordering", [])) > 0 - ), f"Django model {model._meta.app_label}.{model.__name__} has to have a default ordering to be used in a Connection." return connection_type @property diff --git a/graphene_django/filter/tests/conftest.py b/graphene_django/filter/tests/conftest.py index 8824042e9..a4097b183 100644 --- a/graphene_django/filter/tests/conftest.py +++ b/graphene_django/filter/tests/conftest.py @@ -26,9 +26,6 @@ class Event(models.Model): - class Meta: - ordering = ["pk"] - name = models.CharField(max_length=50) tags = ArrayField(models.CharField(max_length=50)) tag_ids = ArrayField(models.IntegerField()) diff --git a/graphene_django/tests/models.py b/graphene_django/tests/models.py index 821b3701f..ece1bb6db 100644 --- a/graphene_django/tests/models.py +++ b/graphene_django/tests/models.py @@ -5,9 +5,6 @@ class Person(models.Model): - class Meta: - ordering = ["pk"] - name = models.CharField(max_length=30) parent = models.ForeignKey( "self", on_delete=models.CASCADE, null=True, blank=True, related_name="children" @@ -15,9 +12,6 @@ class Meta: class Pet(models.Model): - class Meta: - ordering = ["pk"] - name = models.CharField(max_length=30) age = models.PositiveIntegerField() owner = models.ForeignKey( @@ -37,9 +31,6 @@ class FilmDetails(models.Model): class Film(models.Model): - class Meta: - ordering = ["pk"] - genre = models.CharField( max_length=2, help_text="Genre", @@ -55,9 +46,6 @@ def get_queryset(self): class Reporter(models.Model): - class Meta: - ordering = ["pk"] - first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) email = models.EmailField() diff --git a/graphene_django/tests/test_fields.py b/graphene_django/tests/test_fields.py index caaa6ddf7..0f5b79a0b 100644 --- a/graphene_django/tests/test_fields.py +++ b/graphene_django/tests/test_fields.py @@ -2,12 +2,11 @@ import re import pytest -from django.db.models import Count, Model, Prefetch +from django.db.models import Count, Prefetch from graphene import List, NonNull, ObjectType, Schema, String -from graphene.relay import Node -from ..fields import DjangoConnectionField, DjangoListField +from ..fields import DjangoListField from ..types import DjangoObjectType from .models import ( Article as ArticleModel, @@ -717,34 +716,3 @@ def resolve_articles(root, info): r'SELECT .* FROM "tests_film" INNER JOIN "tests_film_reporters" .* LEFT OUTER JOIN "tests_filmdetails"', captured.captured_queries[1]["sql"], ) - - -class TestDjangoConnectionField: - def test_model_ordering_assertion(self): - class Chaos(Model): - class Meta: - app_label = "test" - - class ChaosType(DjangoObjectType): - class Meta: - model = Chaos - interfaces = (Node,) - - class Query(ObjectType): - chaos = DjangoConnectionField(ChaosType) - - with pytest.raises( - TypeError, - match=r"Django model test\.Chaos has to have a default ordering to be used in a Connection\.", - ): - Schema(query=Query) - - def test_only_django_object_types(self): - class Query(ObjectType): - something = DjangoConnectionField(String) - - with pytest.raises( - TypeError, - match="DjangoConnectionField only accepts DjangoObjectType types as underlying type", - ): - Schema(query=Query) From 28c71c58f73e969bc05ebfdde06f578dd96e15d5 Mon Sep 17 00:00:00 2001 From: Markus Richter Date: Tue, 11 Jun 2024 16:14:54 +0200 Subject: [PATCH 4/4] Bump to 3.2.2 --- graphene_django/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphene_django/__init__.py b/graphene_django/__init__.py index b0e7abd8b..ac15e354a 100644 --- a/graphene_django/__init__.py +++ b/graphene_django/__init__.py @@ -2,7 +2,7 @@ from .types import DjangoObjectType from .utils import bypass_get_queryset -__version__ = "3.2.1" +__version__ = "3.2.2" __all__ = [ "__version__",