strawberry-django
strawberry-django copied to clipboard
Mutation with required foreign key GraphiQL issue
I am having issues referencing the ID for an existing foreign key while bypassing the required inputs fields for the foreign key.
Lets say I have a model
class Address(models.Model):
name = models.CharField()
class Person(models.Model):
name = models.CharField()
address = models.ForeignKey('Address', on_delete=models.CASCADE, blank=False, null=False)
With the type.py file like this
@strawberry.django.type(models.Address)
class Address:
id: auto
name:auto
@strawberry.django.input(models.Address)
class AddressInput:
id: auto
name:auto
@strawberry.django.type(models.Person)
class Person:
id: auto
name: auto
address:'Address'
@strawberry.django.input(models.Person)
class Person:
id: auto
name: auto
address:'AddressInput'
Schema.py
@strawberry.type
class Mutation:
createAddress: Address = mutations.create(AddressInput)
createPerson: Person =mutations.create(PersonInput)
schema = strawberry.Schema(mutation=Mutation)
If I write a query for Person and reference an existing address in the database as an ID on the GraphiQL page like this:
mutation newPerson ($name: String!, $address:ID!){
createPerson(data: {name: $name, address: {id: $address}}) {
id
name
address {
id
name
}
}
}
It will not work because the GraphiQL requires the name field to be inputted in the foreign key.
Describe the Bug
The GraphiQL interface has requirements settings for foreign keys mutations that is not bypassed when referencing an existing id.
In the above example if I wanted to create an new Person object where I have an existing id for address it would still ask for the address name field.
System Information
- Operating system: Windows 10
- Strawberry version (if applicable):.117.1
- Strawberry Django: 0.4
Additional Context
Upvote & Fund
- We're using Polar.sh so you can upvote and help fund this issue.
- We receive the funding once the issue is completed & confirmed by you.
- Thank you in advance for helping prioritize & fund our backlog.
Hey @ccsv ,
The issue here is that using input
with auto
will mark that field as mandatory. You probably need to pass partial=True
to the input
to make sure the name is not mandatory.
@bellini666 Ok it works so it is a docs issue I am going to update it. Here is the PR
@bellini666
Ok so I changed partial=True
and entered my query
mutation newPerson ($name: String!, $address:ID!){
createPerson(data: {name: $name, address: {id: $address}}) {
id
name
address {
id
name
}
}
}
Variables
{
"name": "Test",
"id": 1
}
I got back an error where the ID was being changed to a string by the GraphiQL interface. Note that I defined my id as an int without the quotes.
{
"data": null,
"errors": [
{
"message": "Field 'id' expected a number but got AddressInput(id='1', name=UNSET).",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createPerson"
]
}
]
}
@ccsv if I understood your code correctly, based on the way you declared the mutation at the gql mutation as address: {id: $address}}
, you should be passing only the id
to it. If you declared it as address: $address
then you could pass the object itself containing the id.
@bellini666 That does not work either If I try:
mutation newPerson ($name: String!, $address:ID!){
createPerson(data: {name: $name, address: $address}) {
id
name
address {
id
name
}
}
}
Variables
{
"name": "Test",
"id": 1
}
I get this error
{
"data": null,
"errors": [
{
"message": "Variable '$address' of type 'ID!' used in position expecting type 'AddressInput!'.",
"locations": [
{
"line": 1,
"column": 20
},
{
"line": 2,
"column": 31
}
]
}
]
}
You are forced to declare it as AddressInput in that case. If I try it with AddressInput!
mutation newPerson ($name: String!, $address:AddressInput!){
createPerson(data: {name: $name, address: $address}) {
id
name
address {
id
name
}
}
}
Variables
{
"name": "Test",
"id": 1
}
I get an error because AddressInput has to be an object
{
"data": null,
"errors": [
{
"message": "Variable '$address' got invalid value 1; Expected type 'AddressInput' to be a mapping.",
"locations": [
{
"line": 1,
"column": 20
}
]
}
]
}
@ccsv I may be failing to understand what you want to actually achieve here, but your errors are not bugs but actual errors because they don't match the schema you wrote for python.
If you want to pass the ID only through the variables, you should be doing this:
mutation newPerson ($name: String!, $address: ID!){
createPerson(data: {name: $name, address: {id: $address}}) {
id
name
address {
id
name
}
}
}
That because address
expects an object and not an ID.
Now, if you want this to work:
mutation newPerson ($name: String!, $address: AddressInput!){
createPerson(data: {name: $name, address: $address}) {
id
name
address {
id
name
}
}
}
Then you should pass {"address": {"id": 123}}
to the variable (note that I'm passing an object that matches AddressInput
and not only the id.
@bellini666 I am just doing a mutation where I set the foreign key by using an id. I did the exactly mutation query you have on your second mutation input above.
To confirm I have the foreign key I ran a query which yield this:
{
"data": {
"addresses": [
{
"id": "1",
"name": "Test1"
},
{
"id": "2",
"name": "Test2"
},
{
"id": "15",
"name": "kkk"
}
]
}
}
So I know id =1
exist for address. Then I ran the same mutation you had above:
mutation newPerson ($name: String!, $address: AddressInput!){
createPerson(data: {name: $name, address: $address}) {
id
name
address {
id
name
}
}
}
Variables
{
"address": {"id": 1}
}
and I got this error:
{
"data": null,
"errors": [
{
"message": "Field 'id' expected a number but got AddressInput(id='1', name=UNSET).",
"locations": [
{
"line": 2,
"column": 3
}
],
"path": [
"createPerson"
]
}
]
}
Note that the error has name=UNSET
instead of referencing the address( "id": "1", "name": "Test1"). I don't think this is a user error. If it is my error please show me where my mistake is. I also changed the decorator for AddressInput to @strawberry.django.input(models.Address, partial=True)
as recommended above.