From 788adb281e0326b0f3b6ed783699116ce49d8644 Mon Sep 17 00:00:00 2001 From: Nick Pope Date: Thu, 7 Nov 2024 17:30:56 +0000 Subject: [PATCH] Fix typing of related manager methods Looking at the [related manager documentation][0] it isn't very clear that the `bulk` argument only applies to `RelatedManager` and the `through_defaults` argument only applies to `ManyRelatedManager`. Based on the [related descriptors source][1], the following changes have been made in this commit: - The `bulk` argument has been added to `.clear()` and `.aclear()` for `RelatedManager` - The `bulk` argument has been removed from all methods of `ManyRelatedManager` - Additional methods using `through_defaults` have been added to `ManyRelatedManager`. [0]: https://docs.djangoproject.com/en/stable/ref/models/relations/ [1]: https://github.com/django/django/blob/042b381e2e37c0c37b8a8f6cc9947f1a2ebfa0dd/django/db/models/fields/related_descriptors.py --- .../db/models/fields/related_descriptors.pyi | 84 ++++++++++++++++--- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/django-stubs/db/models/fields/related_descriptors.pyi b/django-stubs/db/models/fields/related_descriptors.pyi index 4deec2d44..622b5cc29 100644 --- a/django-stubs/db/models/fields/related_descriptors.pyi +++ b/django-stubs/db/models/fields/related_descriptors.pyi @@ -102,10 +102,22 @@ class RelatedManager(Manager[_To], Generic[_To]): async def aadd(self, *objs: _To | int, bulk: bool = ...) -> None: ... def remove(self, *objs: _To | int, bulk: bool = ...) -> None: ... async def aremove(self, *objs: _To | int, bulk: bool = ...) -> None: ... - def set(self, objs: QuerySet[_To] | Iterable[_To | int], *, bulk: bool = ..., clear: bool = ...) -> None: ... - async def aset(self, objs: QuerySet[_To] | Iterable[_To | int], *, bulk: bool = ..., clear: bool = ...) -> None: ... - def clear(self) -> None: ... - async def aclear(self) -> None: ... + def clear(self, *, clear: bool = ...) -> None: ... + async def aclear(self, *, clear: bool = ...) -> None: ... + def set( + self, + objs: QuerySet[_To] | Iterable[_To | int], + *, + bulk: bool = ..., + clear: bool = ..., + ) -> None: ... + async def aset( + self, + objs: QuerySet[_To] | Iterable[_To | int], + *, + bulk: bool = ..., + clear: bool = ..., + ) -> None: ... def __call__(self, *, manager: str) -> RelatedManager[_To]: ... def create_reverse_many_to_one_manager( @@ -142,15 +154,24 @@ class ManyToManyDescriptor(ReverseManyToOneDescriptor, Generic[_To, _Through]): class ManyRelatedManager(Manager[_To], Generic[_To, _Through]): related_val: tuple[int, ...] through: type[_Through] - def add(self, *objs: _To | int, bulk: bool = ..., through_defaults: dict[str, Any] | None = ...) -> None: ... - async def aadd(self, *objs: _To | int, bulk: bool = ..., through_defaults: dict[str, Any] | None = ...) -> None: ... - def remove(self, *objs: _To | int, bulk: bool = ...) -> None: ... - async def aremove(self, *objs: _To | int, bulk: bool = ...) -> None: ... + def add( + self, + *objs: _To | int, + through_defaults: dict[str, Any] | None = ..., + ) -> None: ... + async def aadd( + self, + *objs: _To | int, + through_defaults: dict[str, Any] | None = ..., + ) -> None: ... + def remove(self, *objs: _To | int) -> None: ... + async def aremove(self, *objs: _To | int) -> None: ... + def clear(self) -> None: ... + async def aclear(self) -> None: ... def set( self, objs: QuerySet[_To] | Iterable[_To | int], *, - bulk: bool = ..., clear: bool = ..., through_defaults: dict[str, Any] | None = ..., ) -> None: ... @@ -158,12 +179,51 @@ class ManyRelatedManager(Manager[_To], Generic[_To, _Through]): self, objs: QuerySet[_To] | Iterable[_To | int], *, - bulk: bool = ..., clear: bool = ..., through_defaults: dict[str, Any] | None = ..., ) -> None: ... - def clear(self) -> None: ... - async def aclear(self) -> None: ... + def create( + self, + *, + through_defaults: dict[str, Any] | None = ..., + **kwargs: Any, + ) -> _To: ... + async def acreate( + self, + *, + through_defaults: dict[str, Any] | None = ..., + **kwargs: Any, + ) -> _To: ... + def get_or_create( + self, + *, + defaults: Mapping[str, Any] | None = ..., + through_defaults: dict[str, Any] | None = ..., + **kwargs: Any, + ) -> tuple[_To, bool]: ... + async def aget_or_create( + self, + *, + defaults: Mapping[str, Any] | None = ..., + through_defaults: dict[str, Any] | None = ..., + **kwargs: Any, + ) -> tuple[_To, bool]: ... + def update_or_create( + self, + *, + defaults: Mapping[str, Any] | None = ..., + create_defaults: Mapping[str, Any] | None = ..., + through_defaults: dict[str, Any] | None = ..., + **kwargs: Any, + ) -> tuple[_To, bool]: ... + async def aupdate_or_create( + self, + *, + defaults: Mapping[str, Any] | None = ..., + create_defaults: Mapping[str, Any] | None = ..., + through_defaults: dict[str, Any] | None = ..., + **kwargs: Any, + ) -> tuple[_To, bool]: ... def __call__(self, *, manager: str) -> ManyRelatedManager[_To, _Through]: ... def create_forward_many_to_many_manager(