mirror of
				https://github.com/graphql-python/graphene-django.git
				synced 2025-10-31 07:57:31 +03:00 
			
		
		
		
	* Use ruff in pre-commit * Add pyupgrade * Add isort * Add bugbear * Fix B015 Pointless comparison * Fix B026 * B018 false positive * Remove flake8 and isort config from setup.cfg * Remove black and flake8 from dev dependencies * Update black * Show list of fixes applied with autofix on * Fix typo * Add C4 flake8-comprehensions * Add ruff to dev dependencies * Fix up
		
			
				
	
	
		
			565 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			565 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import pytest
 | |
| from graphql_relay import to_global_id
 | |
| 
 | |
| import graphene
 | |
| from graphene.relay import Node
 | |
| 
 | |
| from ..types import DjangoObjectType
 | |
| from .models import Article, Film, FilmDetails, Reporter
 | |
| 
 | |
| 
 | |
| class TestShouldCallGetQuerySetOnForeignKey:
 | |
|     """
 | |
|     Check that the get_queryset method is called in both forward and reversed direction
 | |
|     of a foreignkey on types.
 | |
|     (see issue #1111)
 | |
| 
 | |
|     NOTE: For now, we do not expect this get_queryset method to be called for nested
 | |
|     objects, as the original attempt to do so prevented SQL query-optimization with
 | |
|     `select_related`/`prefetch_related` and caused N+1 queries. See discussions here
 | |
|     https://github.com/graphql-python/graphene-django/pull/1315/files#r1015659857
 | |
|     and here https://github.com/graphql-python/graphene-django/pull/1401.
 | |
|     """
 | |
| 
 | |
|     @pytest.fixture(autouse=True)
 | |
|     def setup_schema(self):
 | |
|         class ReporterType(DjangoObjectType):
 | |
|             class Meta:
 | |
|                 model = Reporter
 | |
| 
 | |
|             @classmethod
 | |
|             def get_queryset(cls, queryset, info):
 | |
|                 if info.context and info.context.get("admin"):
 | |
|                     return queryset
 | |
|                 raise Exception("Not authorized to access reporters.")
 | |
| 
 | |
|         class ArticleType(DjangoObjectType):
 | |
|             class Meta:
 | |
|                 model = Article
 | |
| 
 | |
|             @classmethod
 | |
|             def get_queryset(cls, queryset, info):
 | |
|                 return queryset.exclude(headline__startswith="Draft")
 | |
| 
 | |
|         class Query(graphene.ObjectType):
 | |
|             reporter = graphene.Field(ReporterType, id=graphene.ID(required=True))
 | |
|             article = graphene.Field(ArticleType, id=graphene.ID(required=True))
 | |
| 
 | |
|             def resolve_reporter(self, info, id):
 | |
|                 return (
 | |
|                     ReporterType.get_queryset(Reporter.objects, info)
 | |
|                     .filter(id=id)
 | |
|                     .last()
 | |
|                 )
 | |
| 
 | |
|             def resolve_article(self, info, id):
 | |
|                 return (
 | |
|                     ArticleType.get_queryset(Article.objects, info).filter(id=id).last()
 | |
|                 )
 | |
| 
 | |
|         self.schema = graphene.Schema(query=Query)
 | |
| 
 | |
|         self.reporter = Reporter.objects.create(first_name="Jane", last_name="Doe")
 | |
| 
 | |
|         self.articles = [
 | |
|             Article.objects.create(
 | |
|                 headline="A fantastic article",
 | |
|                 reporter=self.reporter,
 | |
|                 editor=self.reporter,
 | |
|             ),
 | |
|             Article.objects.create(
 | |
|                 headline="Draft: My next best seller",
 | |
|                 reporter=self.reporter,
 | |
|                 editor=self.reporter,
 | |
|             ),
 | |
|         ]
 | |
| 
 | |
|     def test_get_queryset_called_on_field(self):
 | |
|         # If a user tries to access an article it is fine as long as it's not a draft one
 | |
|         query = """
 | |
|             query getArticle($id: ID!) {
 | |
|                 article(id: $id) {
 | |
|                     headline
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
|         # Non-draft
 | |
|         result = self.schema.execute(query, variables={"id": self.articles[0].id})
 | |
|         assert not result.errors
 | |
|         assert result.data["article"] == {
 | |
|             "headline": "A fantastic article",
 | |
|         }
 | |
|         # Draft
 | |
|         result = self.schema.execute(query, variables={"id": self.articles[1].id})
 | |
|         assert not result.errors
 | |
|         assert result.data["article"] is None
 | |
| 
 | |
|         # If a non admin user tries to access a reporter they should get our authorization error
 | |
|         query = """
 | |
|             query getReporter($id: ID!) {
 | |
|                 reporter(id: $id) {
 | |
|                     firstName
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(query, variables={"id": self.reporter.id})
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access reporters."
 | |
| 
 | |
|         # An admin user should be able to get reporters
 | |
|         query = """
 | |
|             query getReporter($id: ID!) {
 | |
|                 reporter(id: $id) {
 | |
|                     firstName
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.reporter.id},
 | |
|             context_value={"admin": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data == {"reporter": {"firstName": "Jane"}}
 | |
| 
 | |
|     def test_get_queryset_called_on_foreignkey(self):
 | |
|         # If a user tries to access a reporter through an article they should get our authorization error
 | |
|         query = """
 | |
|             query getArticle($id: ID!) {
 | |
|                 article(id: $id) {
 | |
|                     headline
 | |
|                     reporter {
 | |
|                         firstName
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(query, variables={"id": self.articles[0].id})
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access reporters."
 | |
| 
 | |
|         # An admin user should be able to get reporters through an article
 | |
|         query = """
 | |
|             query getArticle($id: ID!) {
 | |
|                 article(id: $id) {
 | |
|                     headline
 | |
|                     reporter {
 | |
|                         firstName
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.articles[0].id},
 | |
|             context_value={"admin": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["article"] == {
 | |
|             "headline": "A fantastic article",
 | |
|             "reporter": {"firstName": "Jane"},
 | |
|         }
 | |
| 
 | |
|         # An admin user should not be able to access draft article through a reporter
 | |
|         query = """
 | |
|             query getReporter($id: ID!) {
 | |
|                 reporter(id: $id) {
 | |
|                     firstName
 | |
|                     articles {
 | |
|                         headline
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.reporter.id},
 | |
|             context_value={"admin": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["reporter"] == {
 | |
|             "firstName": "Jane",
 | |
|             "articles": [{"headline": "A fantastic article"}],
 | |
|         }
 | |
| 
 | |
| 
 | |
| class TestShouldCallGetQuerySetOnForeignKeyNode:
 | |
|     """
 | |
|     Check that the get_queryset method is called in both forward and reversed direction
 | |
|     of a foreignkey on types using a node interface.
 | |
|     (see issue #1111)
 | |
|     """
 | |
| 
 | |
|     @pytest.fixture(autouse=True)
 | |
|     def setup_schema(self):
 | |
|         class ReporterType(DjangoObjectType):
 | |
|             class Meta:
 | |
|                 model = Reporter
 | |
|                 interfaces = (Node,)
 | |
| 
 | |
|             @classmethod
 | |
|             def get_queryset(cls, queryset, info):
 | |
|                 if info.context and info.context.get("admin"):
 | |
|                     return queryset
 | |
|                 raise Exception("Not authorized to access reporters.")
 | |
| 
 | |
|         class ArticleType(DjangoObjectType):
 | |
|             class Meta:
 | |
|                 model = Article
 | |
|                 interfaces = (Node,)
 | |
| 
 | |
|             @classmethod
 | |
|             def get_queryset(cls, queryset, info):
 | |
|                 return queryset.exclude(headline__startswith="Draft")
 | |
| 
 | |
|         class Query(graphene.ObjectType):
 | |
|             reporter = Node.Field(ReporterType)
 | |
|             article = Node.Field(ArticleType)
 | |
| 
 | |
|         self.schema = graphene.Schema(query=Query)
 | |
| 
 | |
|         self.reporter = Reporter.objects.create(first_name="Jane", last_name="Doe")
 | |
| 
 | |
|         self.articles = [
 | |
|             Article.objects.create(
 | |
|                 headline="A fantastic article",
 | |
|                 reporter=self.reporter,
 | |
|                 editor=self.reporter,
 | |
|             ),
 | |
|             Article.objects.create(
 | |
|                 headline="Draft: My next best seller",
 | |
|                 reporter=self.reporter,
 | |
|                 editor=self.reporter,
 | |
|             ),
 | |
|         ]
 | |
| 
 | |
|     def test_get_queryset_called_on_node(self):
 | |
|         # If a user tries to access an article it is fine as long as it's not a draft one
 | |
|         query = """
 | |
|             query getArticle($id: ID!) {
 | |
|                 article(id: $id) {
 | |
|                     headline
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
|         # Non-draft
 | |
|         result = self.schema.execute(
 | |
|             query, variables={"id": to_global_id("ArticleType", self.articles[0].id)}
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["article"] == {
 | |
|             "headline": "A fantastic article",
 | |
|         }
 | |
|         # Draft
 | |
|         result = self.schema.execute(
 | |
|             query, variables={"id": to_global_id("ArticleType", self.articles[1].id)}
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["article"] is None
 | |
| 
 | |
|         # If a non admin user tries to access a reporter they should get our authorization error
 | |
|         query = """
 | |
|             query getReporter($id: ID!) {
 | |
|                 reporter(id: $id) {
 | |
|                     firstName
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query, variables={"id": to_global_id("ReporterType", self.reporter.id)}
 | |
|         )
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access reporters."
 | |
| 
 | |
|         # An admin user should be able to get reporters
 | |
|         query = """
 | |
|             query getReporter($id: ID!) {
 | |
|                 reporter(id: $id) {
 | |
|                     firstName
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": to_global_id("ReporterType", self.reporter.id)},
 | |
|             context_value={"admin": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data == {"reporter": {"firstName": "Jane"}}
 | |
| 
 | |
|     def test_get_queryset_called_on_foreignkey(self):
 | |
|         # If a user tries to access a reporter through an article they should get our authorization error
 | |
|         query = """
 | |
|             query getArticle($id: ID!) {
 | |
|                 article(id: $id) {
 | |
|                     headline
 | |
|                     reporter {
 | |
|                         firstName
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query, variables={"id": to_global_id("ArticleType", self.articles[0].id)}
 | |
|         )
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access reporters."
 | |
| 
 | |
|         # An admin user should be able to get reporters through an article
 | |
|         query = """
 | |
|             query getArticle($id: ID!) {
 | |
|                 article(id: $id) {
 | |
|                     headline
 | |
|                     reporter {
 | |
|                         firstName
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": to_global_id("ArticleType", self.articles[0].id)},
 | |
|             context_value={"admin": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["article"] == {
 | |
|             "headline": "A fantastic article",
 | |
|             "reporter": {"firstName": "Jane"},
 | |
|         }
 | |
| 
 | |
|         # An admin user should not be able to access draft article through a reporter
 | |
|         query = """
 | |
|             query getReporter($id: ID!) {
 | |
|                 reporter(id: $id) {
 | |
|                     firstName
 | |
|                     articles {
 | |
|                         edges {
 | |
|                             node {
 | |
|                                 headline
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": to_global_id("ReporterType", self.reporter.id)},
 | |
|             context_value={"admin": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["reporter"] == {
 | |
|             "firstName": "Jane",
 | |
|             "articles": {"edges": [{"node": {"headline": "A fantastic article"}}]},
 | |
|         }
 | |
| 
 | |
| 
 | |
| class TestShouldCallGetQuerySetOnOneToOne:
 | |
|     @pytest.fixture(autouse=True)
 | |
|     def setup_schema(self):
 | |
|         class FilmDetailsType(DjangoObjectType):
 | |
|             class Meta:
 | |
|                 model = FilmDetails
 | |
| 
 | |
|             @classmethod
 | |
|             def get_queryset(cls, queryset, info):
 | |
|                 if info.context and info.context.get("permission_get_film_details"):
 | |
|                     return queryset
 | |
|                 raise Exception("Not authorized to access film details.")
 | |
| 
 | |
|         class FilmType(DjangoObjectType):
 | |
|             class Meta:
 | |
|                 model = Film
 | |
| 
 | |
|             @classmethod
 | |
|             def get_queryset(cls, queryset, info):
 | |
|                 if info.context and info.context.get("permission_get_film"):
 | |
|                     return queryset
 | |
|                 raise Exception("Not authorized to access film.")
 | |
| 
 | |
|         class Query(graphene.ObjectType):
 | |
|             film_details = graphene.Field(
 | |
|                 FilmDetailsType, id=graphene.ID(required=True)
 | |
|             )
 | |
|             film = graphene.Field(FilmType, id=graphene.ID(required=True))
 | |
| 
 | |
|             def resolve_film_details(self, info, id):
 | |
|                 return (
 | |
|                     FilmDetailsType.get_queryset(FilmDetails.objects, info)
 | |
|                     .filter(id=id)
 | |
|                     .last()
 | |
|                 )
 | |
| 
 | |
|             def resolve_film(self, info, id):
 | |
|                 return FilmType.get_queryset(Film.objects, info).filter(id=id).last()
 | |
| 
 | |
|         self.schema = graphene.Schema(query=Query)
 | |
| 
 | |
|         self.films = [
 | |
|             Film.objects.create(
 | |
|                 genre="do",
 | |
|             ),
 | |
|             Film.objects.create(
 | |
|                 genre="ac",
 | |
|             ),
 | |
|         ]
 | |
| 
 | |
|         self.film_details = [
 | |
|             FilmDetails.objects.create(
 | |
|                 film=self.films[0],
 | |
|             ),
 | |
|             FilmDetails.objects.create(
 | |
|                 film=self.films[1],
 | |
|             ),
 | |
|         ]
 | |
| 
 | |
|     def test_get_queryset_called_on_field(self):
 | |
|         # A user tries to access a film
 | |
|         query = """
 | |
|             query getFilm($id: ID!) {
 | |
|                 film(id: $id) {
 | |
|                     genre
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         # With `permission_get_film`
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.films[0].id},
 | |
|             context_value={"permission_get_film": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data["film"] == {
 | |
|             "genre": "DO",
 | |
|         }
 | |
| 
 | |
|         # Without `permission_get_film`
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.films[1].id},
 | |
|             context_value={"permission_get_film": False},
 | |
|         )
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access film."
 | |
| 
 | |
|         # A user tries to access a film details
 | |
|         query = """
 | |
|             query getFilmDetails($id: ID!) {
 | |
|                 filmDetails(id: $id) {
 | |
|                     location
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         # With `permission_get_film`
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.film_details[0].id},
 | |
|             context_value={"permission_get_film_details": True},
 | |
|         )
 | |
|         assert not result.errors
 | |
|         assert result.data == {"filmDetails": {"location": ""}}
 | |
| 
 | |
|         # Without `permission_get_film`
 | |
|         result = self.schema.execute(
 | |
|             query,
 | |
|             variables={"id": self.film_details[0].id},
 | |
|             context_value={"permission_get_film_details": False},
 | |
|         )
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access film details."
 | |
| 
 | |
|     def test_get_queryset_called_on_foreignkey(self, django_assert_num_queries):
 | |
|         # A user tries to access a film details through a film
 | |
|         query = """
 | |
|             query getFilm($id: ID!) {
 | |
|                 film(id: $id) {
 | |
|                     genre
 | |
|                     details {
 | |
|                         location
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         # With `permission_get_film_details`
 | |
|         with django_assert_num_queries(2):
 | |
|             result = self.schema.execute(
 | |
|                 query,
 | |
|                 variables={"id": self.films[0].id},
 | |
|                 context_value={
 | |
|                     "permission_get_film": True,
 | |
|                     "permission_get_film_details": True,
 | |
|                 },
 | |
|             )
 | |
|         assert not result.errors
 | |
|         assert result.data["film"] == {
 | |
|             "genre": "DO",
 | |
|             "details": {"location": ""},
 | |
|         }
 | |
| 
 | |
|         # Without `permission_get_film_details`
 | |
|         with django_assert_num_queries(1):
 | |
|             result = self.schema.execute(
 | |
|                 query,
 | |
|                 variables={"id": self.films[0].id},
 | |
|                 context_value={
 | |
|                     "permission_get_film": True,
 | |
|                     "permission_get_film_details": False,
 | |
|                 },
 | |
|             )
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access film details."
 | |
| 
 | |
|         # A user tries to access a film through a film details
 | |
|         query = """
 | |
|             query getFilmDetails($id: ID!) {
 | |
|                 filmDetails(id: $id) {
 | |
|                     location
 | |
|                     film {
 | |
|                         genre
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         """
 | |
| 
 | |
|         # With `permission_get_film`
 | |
|         with django_assert_num_queries(2):
 | |
|             result = self.schema.execute(
 | |
|                 query,
 | |
|                 variables={"id": self.film_details[0].id},
 | |
|                 context_value={
 | |
|                     "permission_get_film": True,
 | |
|                     "permission_get_film_details": True,
 | |
|                 },
 | |
|             )
 | |
|         assert not result.errors
 | |
|         assert result.data["filmDetails"] == {
 | |
|             "location": "",
 | |
|             "film": {"genre": "DO"},
 | |
|         }
 | |
| 
 | |
|         # Without `permission_get_film`
 | |
|         with django_assert_num_queries(1):
 | |
|             result = self.schema.execute(
 | |
|                 query,
 | |
|                 variables={"id": self.film_details[1].id},
 | |
|                 context_value={
 | |
|                     "permission_get_film": False,
 | |
|                     "permission_get_film_details": True,
 | |
|                 },
 | |
|             )
 | |
|         assert len(result.errors) == 1
 | |
|         assert result.errors[0].message == "Not authorized to access film."
 |