-
-
Notifications
You must be signed in to change notification settings - Fork 575
Manager with generic QuerySet using TypeVar defaults
#2776
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
Draft
UnknownPlatypus
wants to merge
15
commits into
typeddjango:master
Choose a base branch
from
UnknownPlatypus:managers-with-generic-querysets-3
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
519ea77
Add queryset second type param to Manager
UnknownPlatypus 274ca0b
Update plugin code to fill Manager QS second type param
UnknownPlatypus 24e970f
Extract through table manager creation from `create_through_table_class`
UnknownPlatypus 176f2f3
Reparametrize custom untyped queryset class like in #1169
UnknownPlatypus 13850f1
Extend troubleshooting guide around QS and Manager annotations
UnknownPlatypus 44176ee
Update test snapshots with queryset type param
UnknownPlatypus 911f922
Add assert_type test for `create_reverse_many_to_one_manager`
UnknownPlatypus 0579b7d
Extend `override_manager_create` test to showcase expected failure
UnknownPlatypus 499f315
Add regression test for 2602
UnknownPlatypus aba2a80
Add regression test for #1023
UnknownPlatypus 450cea7
Add regression test for #728
UnknownPlatypus da3bcf3
Add regression test for #1067
UnknownPlatypus 68bc3a2
Use more accurate return Self when testing unions
UnknownPlatypus bdcdc60
Add regression test for #1918
UnknownPlatypus 00ae6fe
Amend README
UnknownPlatypus File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,13 +8,15 @@ from django.db.models.query import QuerySet, RawQuerySet | |
| from typing_extensions import Self | ||
|
|
||
| _T = TypeVar("_T", bound=Model, covariant=True) | ||
| _QS = TypeVar("_QS", bound=QuerySet[Any], covariant=True, default=QuerySet[_T]) | ||
|
|
||
| class BaseManager(Generic[_T]): | ||
| class BaseManager(Generic[_T, _QS]): | ||
| creation_counter: int | ||
| auto_created: bool | ||
| use_in_migrations: bool | ||
| name: str | ||
| model: type[_T] | ||
| _queryset_class: type[_QS] | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I needed to expose this symbol because I use it in the plugin. |
||
| _db: str | None | ||
| def __new__(cls, *args: Any, **kwargs: Any) -> Self: ... | ||
| def __init__(self) -> None: ... | ||
|
|
@@ -24,17 +26,25 @@ class BaseManager(Generic[_T]): | |
| ) -> tuple[bool, str | None, str | None, Sequence[Any] | None, dict[str, Any] | None]: ... | ||
| def check(self, **kwargs: Any) -> list[Any]: ... | ||
| @classmethod | ||
| def from_queryset(cls, queryset_class: type[QuerySet[_T]], class_name: str | None = None) -> type[Self]: ... | ||
| def from_queryset( | ||
| cls, queryset_class: type[QuerySet[_T]], class_name: str | None = None | ||
| ) -> type[BaseManager[_T, _QS]]: ... | ||
| @classmethod | ||
| def _get_queryset_methods(cls, queryset_class: type) -> dict[str, Any]: ... | ||
| def contribute_to_class(self, cls: type[Model], name: str) -> None: ... | ||
| def db_manager(self, using: str | None = None, hints: dict[str, Model] | None = None) -> Self: ... | ||
| @property | ||
| def db(self) -> str: ... | ||
| def get_queryset(self) -> QuerySet[_T]: ... | ||
| def all(self) -> QuerySet[_T]: ... | ||
| def get_queryset(self) -> _QS: ... | ||
| def all(self) -> _QS: ... | ||
|
|
||
| class Manager(BaseManager[_T]): | ||
| class Manager(BaseManager[_T, _QS]): | ||
| # `from_queryset` is redeclared here because Self cannot have type arguments | ||
| # ie `def from_queryset(...) -> type[Self[_T, _QS]]` is not valid (mypy raises an error, but resolves type correctly) | ||
| @classmethod | ||
| def from_queryset( | ||
| cls, queryset_class: type[QuerySet[_T]], class_name: str | None = None | ||
| ) -> type[Manager[_T, _QS]]: ... | ||
| # NOTE: The following methods are in common with QuerySet, but note that the use of QuerySet as a return type | ||
| # rather than a self-type (_QS), since Manager's QuerySet-like methods return QuerySets and not Managers. | ||
| def iterator(self, chunk_size: int | None = ...) -> Iterator[_T]: ... | ||
|
|
@@ -112,24 +122,24 @@ class Manager(BaseManager[_T]): | |
| def datetimes( | ||
| self, field_name: str, kind: str, order: str = ..., tzinfo: datetime.tzinfo | None = ... | ||
| ) -> QuerySet[_T, datetime.datetime]: ... | ||
| def none(self) -> QuerySet[_T]: ... | ||
| def filter(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ... | ||
| def exclude(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ... | ||
| def complex_filter(self, filter_obj: Any) -> QuerySet[_T]: ... | ||
| def none(self) -> _QS: ... | ||
| def filter(self, *args: Any, **kwargs: Any) -> _QS: ... | ||
| def exclude(self, *args: Any, **kwargs: Any) -> _QS: ... | ||
| def complex_filter(self, filter_obj: Any) -> _QS: ... | ||
| def count(self) -> int: ... | ||
| async def acount(self) -> int: ... | ||
| def union(self, *other_qs: Any, all: bool = ...) -> QuerySet[_T]: ... | ||
| def intersection(self, *other_qs: Any) -> QuerySet[_T]: ... | ||
| def difference(self, *other_qs: Any) -> QuerySet[_T]: ... | ||
| def select_for_update( | ||
| self, nowait: bool = ..., skip_locked: bool = ..., of: Sequence[str] = ..., no_key: bool = ... | ||
| ) -> QuerySet[_T]: ... | ||
| def select_related(self, *fields: Any) -> QuerySet[_T]: ... | ||
| def prefetch_related(self, *lookups: Any) -> QuerySet[_T]: ... | ||
| def annotate(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ... | ||
| def alias(self, *args: Any, **kwargs: Any) -> QuerySet[_T]: ... | ||
| def order_by(self, *field_names: Any) -> QuerySet[_T]: ... | ||
| def distinct(self, *field_names: Any) -> QuerySet[_T]: ... | ||
| ) -> _QS: ... | ||
| def select_related(self, *fields: Any) -> _QS: ... | ||
| def prefetch_related(self, *lookups: Any) -> _QS: ... | ||
| def annotate(self, *args: Any, **kwargs: Any) -> _QS: ... | ||
| def alias(self, *args: Any, **kwargs: Any) -> _QS: ... | ||
| def order_by(self, *field_names: Any) -> _QS: ... | ||
| def distinct(self, *field_names: Any) -> _QS: ... | ||
| # extra() return type won't be supported any time soon | ||
| def extra( | ||
| self, | ||
|
|
@@ -141,9 +151,9 @@ class Manager(BaseManager[_T]): | |
| select_params: Sequence[Any] | None = ..., | ||
| ) -> QuerySet[Any]: ... | ||
| def reverse(self) -> QuerySet[_T]: ... | ||
| def defer(self, *fields: Any) -> QuerySet[_T]: ... | ||
| def only(self, *fields: Any) -> QuerySet[_T]: ... | ||
| def using(self, alias: str | None) -> QuerySet[_T]: ... | ||
| def defer(self, *fields: Any) -> _QS: ... | ||
| def only(self, *fields: Any) -> _QS: ... | ||
| def using(self, alias: str | None) -> _QS: ... | ||
|
|
||
| class ManagerDescriptor: | ||
| manager: BaseManager | ||
|
|
@@ -153,5 +163,9 @@ class ManagerDescriptor: | |
| @overload | ||
| def __get__(self, instance: Model, cls: type[Model] | None = None) -> NoReturn: ... | ||
|
|
||
| class EmptyManager(Manager[_T]): | ||
| def __init__(self, model: type[_T]) -> None: ... | ||
| # We have to define different typevars here otherwise it conflicts with the ones above | ||
| _T2 = TypeVar("_T2", bound=Model, covariant=True) | ||
| _QS2 = TypeVar("_QS2", bound=QuerySet[Any], covariant=True, default=QuerySet[_T2]) | ||
|
|
||
| class EmptyManager(Manager[_T2, _QS2]): | ||
| def __init__(self, model: type[_T2]) -> None: ... | ||
|
UnknownPlatypus marked this conversation as resolved.
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.