|
1 | | -from collections.abc import Callable |
2 | | -from typing import Any, Generic, TypeVar, overload |
| 1 | +from collections.abc import Callable, Iterable |
| 2 | +from typing import Any, Generic, NoReturn, TypeVar, overload |
3 | 3 |
|
4 | 4 | from django.core.exceptions import ObjectDoesNotExist |
5 | 5 | from django.db.models.base import Model |
6 | 6 | from django.db.models.fields import Field |
7 | | -from django.db.models.fields.related import ForeignKey, RelatedField |
| 7 | +from django.db.models.fields.related import ForeignKey, ManyToManyField, RelatedField |
8 | 8 | from django.db.models.fields.reverse_related import ManyToManyRel, ManyToOneRel, OneToOneRel |
9 | | -from django.db.models.manager import RelatedManager |
| 9 | +from django.db.models.manager import BaseManager, RelatedManager |
10 | 10 | from django.db.models.query import QuerySet |
11 | 11 | from django.db.models.query_utils import DeferredAttribute |
| 12 | +from typing_extensions import Self |
12 | 13 |
|
13 | | -_T = TypeVar("_T") |
| 14 | +_M = TypeVar("_M", bound=Model) |
14 | 15 | _F = TypeVar("_F", bound=Field) |
15 | 16 | _From = TypeVar("_From", bound=Model) |
16 | 17 | _To = TypeVar("_To", bound=Model) |
@@ -65,28 +66,63 @@ class ReverseOneToOneDescriptor(Generic[_From, _To]): |
65 | 66 | def __reduce__(self) -> tuple[Callable[..., Any], tuple[type[_To], str]]: ... |
66 | 67 |
|
67 | 68 | class ReverseManyToOneDescriptor: |
| 69 | + """ |
| 70 | + In the example:: |
| 71 | +
|
| 72 | + class Child(Model): |
| 73 | + parent = ForeignKey(Parent, related_name='children') |
| 74 | +
|
| 75 | + ``Parent.children`` is a ``ReverseManyToOneDescriptor`` instance. |
| 76 | + """ |
| 77 | + |
68 | 78 | rel: ManyToOneRel |
69 | 79 | field: ForeignKey |
70 | 80 | def __init__(self, rel: ManyToOneRel) -> None: ... |
71 | 81 | @property |
72 | | - def related_manager_cls(self) -> type[RelatedManager]: ... |
73 | | - def __get__(self, instance: Model | None, cls: type[Model] | None = ...) -> ReverseManyToOneDescriptor: ... |
74 | | - def __set__(self, instance: Model, value: list[Model]) -> Any: ... |
| 82 | + def related_manager_cls(self) -> type[RelatedManager[Any]]: ... |
| 83 | + @overload |
| 84 | + def __get__(self, instance: None, cls: Any = ...) -> Self: ... |
| 85 | + @overload |
| 86 | + def __get__(self, instance: Model, cls: Any = ...) -> type[RelatedManager[Any]]: ... |
| 87 | + def __set__(self, instance: Any, value: Any) -> NoReturn: ... |
| 88 | + |
| 89 | +def create_reverse_many_to_one_manager( |
| 90 | + superclass: type[BaseManager[_M]], rel: ManyToOneRel |
| 91 | +) -> type[RelatedManager[_M]]: ... |
75 | 92 |
|
76 | | -def create_reverse_many_to_one_manager(superclass: type, rel: Any) -> type[RelatedManager]: ... |
| 93 | +class ManyToManyDescriptor(ReverseManyToOneDescriptor, Generic[_M]): |
| 94 | + """ |
| 95 | + In the example:: |
| 96 | +
|
| 97 | + class Pizza(Model): |
| 98 | + toppings = ManyToManyField(Topping, related_name='pizzas') |
| 99 | +
|
| 100 | + ``Pizza.toppings`` and ``Topping.pizzas`` are ``ManyToManyDescriptor`` |
| 101 | + instances. |
| 102 | + """ |
77 | 103 |
|
78 | | -class ManyToManyDescriptor(ReverseManyToOneDescriptor, Generic[_F]): |
79 | | - field: _F # type: ignore[assignment] |
| 104 | + # 'field' here is 'rel.field' |
80 | 105 | rel: ManyToManyRel # type: ignore[assignment] |
| 106 | + field: ManyToManyField[Any, _M] # type: ignore[assignment] |
81 | 107 | reverse: bool |
82 | 108 | def __init__(self, rel: ManyToManyRel, reverse: bool = ...) -> None: ... |
83 | 109 | @property |
84 | | - def through(self) -> type[Model]: ... |
| 110 | + def through(self) -> type[_M]: ... |
85 | 111 | @property |
86 | | - def related_manager_cls(self) -> type[Any]: ... # ManyRelatedManager |
| 112 | + def related_manager_cls(self) -> type[ManyRelatedManager[Any]]: ... # type: ignore[override] |
87 | 113 |
|
88 | | -# fake |
89 | | -class _ForwardManyToManyManager(Generic[_T]): |
90 | | - def all(self) -> QuerySet: ... |
| 114 | +class ManyRelatedManager(BaseManager[_M], Generic[_M]): |
| 115 | + related_val: tuple[int, ...] |
| 116 | + def add(self, *objs: _M | int, bulk: bool = ...) -> None: ... |
| 117 | + async def aadd(self, *objs: _M | int, bulk: bool = ...) -> None: ... |
| 118 | + def remove(self, *objs: _M | int, bulk: bool = ...) -> None: ... |
| 119 | + async def aremove(self, *objs: _M | int, bulk: bool = ...) -> None: ... |
| 120 | + def set(self, objs: QuerySet[_M] | Iterable[_M | int], *, bulk: bool = ..., clear: bool = ...) -> None: ... |
| 121 | + async def aset(self, objs: QuerySet[_M] | Iterable[_M | int], *, bulk: bool = ..., clear: bool = ...) -> None: ... |
| 122 | + def clear(self) -> None: ... |
| 123 | + async def aclear(self) -> None: ... |
| 124 | + def __call__(self, *, manager: str) -> ManyRelatedManager[_M]: ... |
91 | 125 |
|
92 | | -def create_forward_many_to_many_manager(superclass: type, rel: Any, reverse: Any) -> _ForwardManyToManyManager: ... |
| 126 | +def create_forward_many_to_many_manager( |
| 127 | + superclass: type[BaseManager[_M]], rel: ManyToManyRel, reverse: bool |
| 128 | +) -> type[ManyRelatedManager[_M]]: ... |
0 commit comments