Mutations

Getting started

Mutations can be defined the same way as strawberryโ€™s mutations , but instead of using @strawberry.mutation , use @strawberry_django.mutation .

Here are the differences between those:

Django errors handling

When defining a mutation you can pass handle_django_errors=True to make it handle common django errors, such as ValidationError , PermissionDenied and ObjectDoesNotExist :

types.py
@strawberry.type
class Mutation:
@strawberry_django.mutation(handle_django_errors=True)
def create_fruit(self, name: str, color: str) -> Fruit:
if not is_valid_color(color):
raise ValidationError("The color is not valid")
# Creation can also raise ValidationError, if the `name` is
# larger than its allowed `max_length` for example.
fruit = models.Fruit.objects.create(name=name)
return cast(Fruit, fruit)

The code above would generate following schema:

schema.graphql
enum OperationMessageKind {
INFO
WARNING
ERROR
PERMISSION
VALIDATION
}
type OperationInfo {
"""List of messages returned by the operation."""
messages: [OperationMessage!]!
}
type OperationMessage {
"""The kind of this message."""
kind: OperationMessageKind!
"""The error message."""
message: String!
"""
The field that caused the error, or `null` if it isn't associated with any particular field.
"""
field: String
"""The error code, or `null` if no error code was set."""
code: String
}
type Fruit {
name: String!
color: String!
}
union CreateFruitPayload = Fruit | OperationInfo
mutation {
createFruit(
name: String!
color: String!
): CreateFruitPayload!
}

Tip

If all or most of your mutations use this behaviour, you can change the default behaviour for handle_django_errors by setting MUTATIONS_DEFAULT_HANDLE_ERRORS=True in your strawberry django settings

Input mutations

Those are defined using @strawberry_django.input_mutation and act the same way as the @strawberry_django.mutation , the only difference being that it injects an InputMutationExtension in the field, which converts its arguments in a new type (check the extensionโ€™s docs for more information).

CUD mutations

The following CUD mutations are provided by this lib:

A basic example would be:

types.py
from strawberry import auto
from strawberry_django import mutations, NodeInput
from strawberry.relay import Node
@strawberry_django.type(SomeModel)
class SomeModelType(Node):
name: auto
@strawberry_django.input(SomeModel)
class SomeModelInput:
name: auto
@strawberry_django.partial(SomeModel)
class SomeModelInputPartial(NodeInput):
name: auto
@strawberry.type
class Mutation:
create_model: SomeModelType = mutations.create(SomeModelInput)
update_model: SomeModelType = mutations.update(SomeModelInputPartial)
delete_model: SomeModelType = mutations.delete(NodeInput)

Some things to note here:

@strawberry_django.partial(SomeModel)
class SomeModelInputPartial:
unique_field: strawberry.auto
@strawberry.type
class Mutation:
update_model: SomeModelType = mutations.update(
SomeModelInputPartial,
key_attr="unique_field",
)
delete_model: SomeModelType = mutations.delete(
SomeModelInputPartial,
key_attr="unique_field",
)

Filtering

Caution

Filtering on mutations is discouraged as it can potentially alter your entire model collection if there are issues with the filters.

Filters can be added to update and delete mutations. More information in the filtering section.

schema.py
import strawberry
from strawberry_django import mutations
@strawberry.type
class Mutation:
updateFruits: list[Fruit] = mutations.update(FruitPartialInput, filters=FruitFilter)
deleteFruits: list[Fruit] = mutations.delete(filters=FruitFilter)
schema = strawberry.Schema(mutation=Mutation)

Batching

If you need to make multiple creates, updates, or deletes as part of one atomic mutation you can use batching. Batching has a similar syntax except that the mutations take and return a list.

schema.py
import strawberry
from strawberry_django import mutations
@strawberry.type
class Mutation:
createFruits: list[Fruit] = mutations.create(list[FruitPartialInput])
updateFruits: list[Fruit] = mutations.update(list[FruitPartialInput])
deleteFruits: list[Fruit] = mutations.delete(list[FruitPartialInput])
schema = strawberry.Schema(mutation=Mutation)