Skip to content
This repository has been archived by the owner on Jul 8, 2023. It is now read-only.

Query optimization based on type hints for non-model fields? #154

Open
blueyed opened this issue Dec 16, 2022 · 4 comments
Open

Query optimization based on type hints for non-model fields? #154

blueyed opened this issue Dec 16, 2022 · 4 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@blueyed
Copy link
Contributor

blueyed commented Dec 16, 2022

A field that represents a model property will not be handled by the query optimizer:

# Lastly, from the django field itself
model_fieldname: str = getattr(field, "django_name", None) or field.python_name
model_field = model_fields.get(model_fieldname, None)
if model_field is not None:

It could get derived from the type hint though, couldn't it?

Specifying field_name, which gets translated into django_name works.
Is this supposed to work like/for this?
Are there unwanted side effects given that it is of type Foo, but not necessarily the actual foreign key / linked object?

    special_foo: Foo = gql.django.field(
        field_name="foo",  # workaround? other side effects?
    )

As for now I am happy with adding only/select_related manually (related: #152).

@blueyed
Copy link
Contributor Author

blueyed commented Dec 16, 2022

side effects?

There are..

For now I can work with using only={"foo__archived"}, to help the function, which uses that property.

@bellini666
Copy link
Member

Hey @blueyed ,

Hrm, we can probably try to do something like that. But having said that, have you take a look at model properties?

You can use it to create a @property in your model, and it accepts optimizer hints. Then on your type you can use that_property_attr: auto. I use that a lot!

@bellini666 bellini666 added enhancement New feature or request help wanted Extra attention is needed labels Dec 19, 2022
frleb pushed a commit to frleb/strawberry-django-plus that referenced this issue Feb 28, 2023
@blueyed
Copy link
Contributor Author

blueyed commented Mar 3, 2023

@bellini666
I think model properties do not help here: the issue is that there is a property, which returns a special "Bar" object via a property/function, and the optimizer does not automatically apply prefetch_related for related objects from there (although the return type indicates that).

My workaround now is to use get_queryset:

@django_type(models.StageRecipe, filters=StageRecipeFilter, pagination=True)
class Bar:
    bar: Bar

    @gql.django.field(
        select_related=[
            "foo__current_version",
        ],
        only=[
            "foo__current_version",
        ],
    )
    def current_foo(self) -> Foo | None:
        return self.foo.current_version

    @classmethod
    def get_queryset(cls, queryset, info, **kwargs):
        qs = queryset.exclude(operational_recipe__status=RecipeStatus.DRAFT)

        for selected_field in info.selected_fields:
            if selected_field.name != "bars":
                continue
            for selected_field2 in selected_field.selections:
                if selected_field2.name != "currentFoo":
                    continue
                for selected_field3 in selected_field2.selections:
                    if selected_field3.name == "baz":
                        qs = qs.prefetch_related("Foo__current_version__baz")

        ...
        return qs
@django_type(
    models.Bar,
    pagination=True,
    only=[
        "status",  # for ConcurrentTransitionMixin.
        "current_version",
    ],
)
class Bar:
    baz: list["Bar"]

@bellini666
Copy link
Member

Hrmm, that __baz is inside a hint and not being discovered by the automatic optimizer

I probably need to find a way to handle those.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants