Skip to content
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

Related Manager lose typing #1918

Open
trecouvr opened this issue Jan 24, 2024 · 0 comments
Open

Related Manager lose typing #1918

trecouvr opened this issue Jan 24, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@trecouvr
Copy link

trecouvr commented Jan 24, 2024

Bug report

Hi, not sure if this is a bug or my having wrong declarations.

What's wrong

The typing of related_manager.all is off when I share a QuerySet between multiple models :

-   case: related
    main: |
        from myapp.models import MyModel
        reveal_type(MyModel.objects.all()) # N: Revealed type is "myapp.models.MyQuerySet[myapp.models.MyModel]"
        reveal_type(list(MyModel.objects.all())[0]) # N: Revealed type is "myapp.models.MyModel"
        for x in MyModel.objects.all():
            reveal_type(x) # N: Revealed type is "myapp.models.MyModel"
            reveal_type(x.relatedobject_set.all()) # N: Revealed type is "myapp.models.MyQuerySet[myapp.models.RelatedObject]"
            reveal_type(list(x.relatedobject_set.all())[0]) # N: Revealed type is "myapp.models.RelatedObject"
            for y in x.relatedobject_set.all():
                reveal_type(y) # N: Revealed type is "myapp.models.RelatedObject"

    installed_apps:
        - myapp
    files:
        -   path: myapp/__init__.py
        -   path: myapp/models.py
            content: |
                from django.db import models
                from django.db.models.manager import BaseManager
                from typing import List, Dict
                from typing_extensions import Self
                from typing import TypeVar, Generic

                T = TypeVar("T", bound=models.Model)

                class MyQuerySet(models.QuerySet[T], Generic[T]): ...

                class MyModel(models.Model):
                    objects = MyQuerySet.as_manager()

                class RelatedObject(models.Model):
                    objects = MyQuerySet.as_manager()
                    parent = models.ForeignKey(MyModel, models.PROTECT)
E   Actual:
E     ...
E     main:6: note: Revealed type is "myapp.models.MyQuerySet" (diff)
E     main:7: note: Revealed type is "T`1"          (diff)
E     main:9: note: Revealed type is "T`1"          (diff)
E     myapp/models:15: error: Need type annotation for "objects"  [var-annotated] (diff)
E     myapp/models:20: error: Need type annotation for "objects"  [var-annotated] (diff)
E   Expected:
E     ...
E     main:6: note: Revealed type is "myapp.models.MyQuerySet[myapp.models.RelatedObject]" (diff)
E     main:7: note: Revealed type is "myapp.models.RelatedObject" (diff)
E     main:9: note: Revealed type is "myapp.models.RelatedObject" (diff)
-   case: related_subclassing
    main: |
        from myapp.models import MyModel
        reveal_type(MyModel.objects.all()) # N: Revealed type is "myapp.models.BaseQuerySet[myapp.models.MyModel]"
        reveal_type(list(MyModel.objects.all())[0]) # N: Revealed type is "myapp.models.MyModel"
        for x in MyModel.objects.all():
            reveal_type(x) # N: Revealed type is "myapp.models.MyModel"
            reveal_type(x.relatedobject_set.all()) # N: Revealed type is "myapp.models.BaseQuerySet[myapp.models.RelatedObject]"
            reveal_type(list(x.relatedobject_set.all())[0]) # N: Revealed type is "myapp.models.RelatedObject"
            for y in x.relatedobject_set.all():
                reveal_type(y) # N: Revealed type is "myapp.models.RelatedObject"

    installed_apps:
        - myapp
    files:
        -   path: myapp/__init__.py
        -   path: myapp/models.py
            content: |
                from django.db import models
                from django.db.models.manager import BaseManager
                from typing import List, Dict
                from typing_extensions import Self
                from typing import TypeVar, Generic

                T = TypeVar("T", bound=models.Model)

                class BaseQuerySet(models.QuerySet[T], Generic[T]): ...

                class BaseModel(models.Model):
                    objects = BaseQuerySet.as_manager()
                    class Meta:
                        abstract = True

                class MyModel(BaseModel):
                    pass

                class RelatedObjectQuerySet(BaseQuerySet["RelatedObject"]):
                    pass

                class RelatedObject(BaseModel):
                    parent = models.ForeignKey(MyModel, models.PROTECT)
E   Actual:
E     ...
E     main:6: note: Revealed type is "myapp.models.BaseQuerySet" (diff)
E     main:7: note: Revealed type is "T`1"          (diff)
E     main:9: note: Revealed type is "T`1"          (diff)
E     myapp/models:13: error: Need type annotation for "objects"  [var-annotated] (diff)
E   Expected:
E     ...
E     main:6: note: Revealed type is "myapp.models.BaseQuerySet[myapp.models.RelatedObject]" (diff)
E     main:7: note: Revealed type is "myapp.models.RelatedObject" (diff)
E     main:9: note: Revealed type is "myapp.models.RelatedObject" (diff)

How is that should be

The types should be MyModel or RelatedObject instead of T.

Note: If I remove the Generic I get Any instead of T.

System information

  • OS: osx
  • python version: 3.11.3
  • django version: Django==4.2.9
  • mypy version: mypy==1.7.1
  • django-stubs version: django-stubs==4.2.7
  • django-stubs-ext version: django-stubs-ext==4.2.7
@trecouvr trecouvr added the bug Something isn't working label Jan 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

1 participant