Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix nested fields update #604
Fix nested fields update #604
Changes from 4 commits
03bbd1b
09fb6b6
f795ddc
5758b68
3354380
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
Check failure on line 265 in strawberry_django/mutations/mutations.py
Check failure on line 326 in strawberry_django/mutations/mutations.py
Check failure on line 387 in strawberry_django/mutations/mutations.py
Check failure on line 103 in strawberry_django/mutations/resolvers.py
Check failure on line 104 in strawberry_django/mutations/resolvers.py
Check failure on line 104 in strawberry_django/mutations/resolvers.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like
pk
may be eitherUNSET
orNone
, in both cases it's necessary to create nested object. And to further properly performfull_clean
andsave
we should identify related model (as in test type hierarchy most models usename
clashing field names, cleaning could pass somehow, but finally object of different type could be created).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this safe? I mean, how can we ensure that
create_kwargs
will identify an object by unique fields?Suppose that we have a model that has a name, and it is not unique nor something that should identify it. Then we get
create_kwargs = {"name": "Foobar"}
. If we already have that object, wouldn't this get that object by mistake instead of creating a new one (which is what we want)?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you are completely right, that is my main concern. Unfortunately an object with
Foobar
name will be returned and no new object created. Django built-inget_or_create
shortcut will do exactly the same, I tried to deep-dive into Django code to find any implementation of identifying all unique fields (FK,unique
prop/other unique constraints), but it seems that's tricky.This idea comes from #360, as I tried to unify nested object creation, something breaks here, either #360 fix or new object creation. I shared my thoughts in the current PR description, could you please also have a look?
The idea to identify all unique fields seems promising, but I'm not sure that we can easily cover all possible scenarios, probably there are some DB-specific tricks also. I could not find any built-in implementation for that, Django
total_unique_constraints
property does not solve that problem.I see two options here to keep both #360 fix and duplicated objects creation:
id=None
in payloadget()
only if unique fields are in the queryPlease share your thoughts. I'd personally prefer option 2, but some more research needed, have some doubts here. Option 1 looks a bit weird, but it's bullet-proof.
Probably option 3 is to remove
get()
and always executefull_clean
followed bycreate
, but it would break #360.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've checked Django code for unique fields validations, there are a few helpful fragments:
unique_together
andtotal_unique_constraints
https://github.com/django/django/blob/9cf9c796be8dd53bc3b11355ff39d65c81d7be6d/django/contrib/admin/views/main.py#L473-L484
unique
field + null checkhttps://github.com/django/django/blob/9cf9c796be8dd53bc3b11355ff39d65c81d7be6d/django/contrib/admin/views/main.py#L441-L445
So what we can try to do is to extract all unique fields using these three "sources" (
unique
,unique_together
andUniqueConstraint
), what do you think? I suppose in case only one of three types is used it should be relatively simple, but in case multiple one are in, that may be tricky.But I still have doubts, should such a logic be a part of the library? Please share your thoughts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although I do like the "identify the unique sources" idea, I'm worried if that could end up reusing some object where we were supposed to create a new one (and if it was unique, the user would maybe expect the code to break)
I'm thinking about a fourth option: What about expanding
key_attr
(or creating another field and deprecating it) to tell the list of fields/field combinations that are to be considered "keys"? Just likeunique_together = [("foo", "bar"), ("bin",)]
for the django modelIn that example, someone could only pass
"bin"
to act like "get_or_create", but("foo", "bar")
would still try to only create, etc.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of using
get_or_create
shortcut I finally came up with a decision to useget
andcreate
separately, but invokefull_clean
only afterget()
is invoked asfull_clean
may raise unique constraint violation exception (e.g. in use case described in #360 )Check failure on line 574 in strawberry_django/mutations/resolvers.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have some doubts here, probably there is any other way to get reverse relationship name.
Check failure on line 589 in strawberry_django/mutations/resolvers.py
Check failure on line 589 in strawberry_django/mutations/resolvers.py
Check failure on line 591 in strawberry_django/mutations/resolvers.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what I was afraid in a previous comment. Should this case be forced to pass
id: null
?name
is not an fk and neither a key that is used to reference the model, so it seems to me that we should not need this change to make this test workThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, unfortunately without explicit
id: null
duplicated object won't be created as Django ORMget(...)
method would return an object found by name.Provided more details in the previous reply: https://github.com/strawberry-graphql/strawberry-django/pull/604/files#r1696994011, let's continue discussion there if you don't mind
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried not to further extend types hierarchy, but this one is required to cover #362 changes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also related to #362 . Not only
unique_together
may be the case but also a single unique field.