Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

DjangoOptimizer prefetch_related on nested objects modifies prefetch #379

Closed
aprams opened this issue Sep 28, 2023 · 0 comments
Closed

DjangoOptimizer prefetch_related on nested objects modifies prefetch #379

aprams opened this issue Sep 28, 2023 · 0 comments
Assignees
Labels
bug Something isn't working

Comments

@aprams
Copy link
Contributor

aprams commented Sep 28, 2023

Describe the Bug

When using the DjangoOptimizer extension and adding prefetching to type's field, the field's store gets corrupted on each query.

Example:

@strawberry_django.type(
    models.MyModel,
)
class MyModelType(RandomPkInterface):
    main_identifier: str = strawberry_django.field(
        field_name="main_identifier",
        prefetch_related=[
            Prefetch(
                "identifiers",
                queryset=Identifiers.objects.all(),
                to_attr="identifiers"
            ),
        ]
    )

Here, I have a custom property on my model that gets the main identifier from all the identifiers, so I want to do a prefetch here to avoid n + 1 issues.

The following query will now cause issues, though:

query {
    myParentObject {
      myModel {
        mainIdentifier
      }
    }
}

Calling this query once works fine, however, the second request will lead to this error:

Cannot find 'my_parent' on MyModel object, 'my_parent_model__my_model__my_parent_model__my_model__identifiers' is an invalid parameter to prefetch_related()

Further subsequent requests each add a my_parent_model__my_model__ to the beginning of the invalid prefetch.

My debugging lead me to the conclusion, that the culprit is line 444 in strawberry-django/optimizer.py :
store |= f_store.with_prefix(path, info=info)

In f_store.with_prefix the actual Prefetch object will prepend the path. This is however a by reference pass of the actual Prefetch object of the field, as this is never copied along the way. This way, after the first call, the prefetch stacks up the prefixes and pollutes/corrupts the field for subsequent calls.

System Information

  • Operating system: Mac OS
  • Strawberry version (if applicable):
  • strawberry-graphql==0.209.0
  • strawberry-graphql-django==0.17.0

Additional Context

My suggestion would be to have a copy of the prefetch object / the field's store when getting it in line 400 in optimizer.py. This would avoid downstream issues.

If you agree with this approach, I can also attempt fixing it as my first issue.

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.
Fund with Polar
@aprams aprams added the bug Something isn't working label Sep 28, 2023
@aprams aprams changed the title DjangoOptimizer prefetch_related on nested objects modifies itself DjangoOptimizer prefetch_related on nested objects modifies prefetch Sep 29, 2023
@bellini666 bellini666 self-assigned this Sep 29, 2023
@aprams aprams closed this as completed Oct 1, 2023
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants