diff --git a/django-stubs/db/models/fields/related_descriptors.pyi b/django-stubs/db/models/fields/related_descriptors.pyi index e3dcdddce..3ac485720 100644 --- a/django-stubs/db/models/fields/related_descriptors.pyi +++ b/django-stubs/db/models/fields/related_descriptors.pyi @@ -1,5 +1,5 @@ from collections.abc import Callable -from typing import Any, Generic, TypeVar +from typing import Any, Generic, overload, Self, TypeVar from django.core.exceptions import ObjectDoesNotExist from django.db.models.base import Model @@ -10,60 +10,75 @@ from django.db.models.fields.reverse_related import ManyToManyRel, OneToOneRel from django.db.models.query import QuerySet _T = TypeVar("_T") +_ModelT = TypeVar("_ModelT", bound=Model) -class ForwardManyToOneDescriptor: +class ForwardManyToOneDescriptor(Generic[_ModelT]): RelatedObjectDoesNotExist: type[ObjectDoesNotExist] field: Field[Any, Any] = ... def __init__(self, field_with_rel: Field[Any, Any]) -> None: ... def is_cached(self, instance: Model) -> bool: ... - def get_queryset(self, **hints: Any) -> QuerySet[Any]: ... + def get_queryset(self, **hints: Any) -> QuerySet[_ModelT]: ... def get_prefetch_queryset( - self, instances: list[Model], queryset: QuerySet[Any] | None = ... + self, instances: list[Model], queryset: QuerySet[_ModelT] | None = ... ) -> tuple[ - QuerySet[Any], Callable[..., Any], Callable[..., Any], bool, str, bool + QuerySet[_ModelT], Callable[..., Any], Callable[..., Any], bool, str, bool ]: ... - def get_object(self, instance: Model) -> Model: ... + def get_object(self, instance: Model) -> _ModelT: ... + @overload def __get__( - self, instance: Model | None, cls: type[Model] = ... - ) -> Model | ForwardManyToOneDescriptor | None: ... - def __set__(self, instance: Model, value: Model | None) -> None: ... + self, instance: None, cls: type[Model] = ... + ) -> Self: ... + @overload + def __get__( + self, instance: Model, cls: type[Model] = ... + ) -> _ModelT: ... + def __set__(self, instance: Model, value: _ModelT | None) -> None: ... def __reduce__(self) -> tuple[Callable[..., Any], tuple[type[Model], str]]: ... -class ForwardOneToOneDescriptor(ForwardManyToOneDescriptor): +class ForwardOneToOneDescriptor(Generic[_ModelT], ForwardManyToOneDescriptor[_ModelT]): RelatedObjectDoesNotExist: type[ObjectDoesNotExist] field: OneToOneField[Any] # pyright: ignore[reportIncompatibleVariableOverride] - def get_object(self, instance: Model) -> Model: ... -class ReverseOneToOneDescriptor: +class ReverseOneToOneDescriptor(Generic[_ModelT]): RelatedObjectDoesNotExist: type[ObjectDoesNotExist] related: OneToOneRel = ... def __init__(self, related: OneToOneRel) -> None: ... def is_cached(self, instance: Model) -> bool: ... - def get_queryset(self, **hints: Any) -> QuerySet[Any]: ... + def get_queryset(self, **hints: Any) -> QuerySet[_ModelT]: ... def get_prefetch_queryset( - self, instances: list[Model], queryset: QuerySet[Any] | None = ... + self, instances: list[Model], queryset: QuerySet[_ModelT] | None = ... ) -> tuple[ - QuerySet[Any], Callable[..., Any], Callable[..., Any], bool, str, bool + QuerySet[_ModelT], Callable[..., Any], Callable[..., Any], bool, str, bool ]: ... + @overload def __get__( - self, instance: Model | None, cls: type[Model] = ... - ) -> Model | ReverseOneToOneDescriptor: ... - def __set__(self, instance: Model, value: Model | None) -> None: ... + self, instance: None, cls: type[Model] = ... + ) -> Self: ... + @overload + def __get__( + self, instance: Model, cls: type[Model] = ... + ) -> _ModelT: ... + def __set__(self, instance: Model, value: _ModelT | None) -> None: ... def __reduce__(self) -> tuple[Callable[..., Any], tuple[type[Model], str]]: ... -class ReverseManyToOneDescriptor: +class ReverseManyToOneDescriptor(Generic[_ModelT]): rel: FieldCacheMixin = ... field: FieldCacheMixin = ... def __init__(self, rel: FieldCacheMixin) -> None: ... def related_manager_cls(self) -> Any: ... + @overload + def __get__( + self, instance: None, cls: type[Model] = ... + ) -> Self: ... + @overload def __get__( self, instance: Model | None, cls: type[Model] = ... - ) -> ReverseManyToOneDescriptor: ... + ) -> _ModelT: ... def __set__(self, instance: Model, value: list[Model]) -> Any: ... def create_reverse_many_to_one_manager(superclass: Any, rel: Any) -> Any: ... -class ManyToManyDescriptor(ReverseManyToOneDescriptor): +class ManyToManyDescriptor(Generic[_ModelT], ReverseManyToOneDescriptor[_ModelT]): field: RelatedField[Any, Any] # pyright: ignore[reportIncompatibleVariableOverride] rel: ManyToManyRel # pyright: ignore[reportIncompatibleVariableOverride] reverse: bool = ...