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

Support returning the correct values for the different QuerySet methods when using .values() and .values_list(). #33

Merged
merged 11 commits into from
Mar 10, 2019
Merged
Next Next commit
Support returning the correct values for the different QuerySet metho…
…ds when using .values() and .values_list().
syastrov committed Feb 28, 2019
commit 6fc4a833cd8d248de17f9c17d96011a42d745f0d
4 changes: 2 additions & 2 deletions django-stubs/db/models/manager.pyi
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ from django.db.models.query import QuerySet

_T = TypeVar("_T", bound=Model, covariant=True)

class BaseManager(QuerySet[_T]):
class BaseManager(QuerySet[_T, _T]):
creation_counter: int = ...
auto_created: bool = ...
use_in_migrations: bool = ...
@@ -21,7 +21,7 @@ class BaseManager(QuerySet[_T]):
def _get_queryset_methods(cls, queryset_class: type) -> Dict[str, Any]: ...
def contribute_to_class(self, model: Type[Model], name: str) -> None: ...
def db_manager(self, using: Optional[str] = ..., hints: Optional[Dict[str, Model]] = ...) -> Manager: ...
def get_queryset(self) -> QuerySet[_T]: ...
def get_queryset(self) -> QuerySet[_T, _T]: ...

class Manager(BaseManager[_T]): ...

80 changes: 40 additions & 40 deletions django-stubs/db/models/query.pyi
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@ from typing import (
TypeVar,
Union,
overload,
Generic,
NamedTuple,
)

from django.db.models.base import Model
@@ -46,7 +48,7 @@ class FlatValuesListIterable(BaseIterable):

_T = TypeVar("_T", bound=models.Model, covariant=True)

class QuerySet(Iterable[_T], Sized):
class QuerySet(Generic[_T, _Row], Sized):
query: Query
def __init__(
self,
@@ -58,32 +60,31 @@ class QuerySet(Iterable[_T], Sized):
@classmethod
def as_manager(cls) -> Manager[Any]: ...
def __len__(self) -> int: ...
def __iter__(self) -> Iterator[_T]: ...
def __iter__(self) -> Iterator[_Row]: ...
def __contains__(self, x: object) -> bool: ...
@overload
def __getitem__(self, i: int) -> _Row: ...
@overload
def __getitem__(self, s: slice) -> Sequence[_Row]: ...
def __bool__(self) -> bool: ...
def __class_getitem__(cls, item: Type[_T]):
pass
def __getstate__(self) -> Dict[str, Any]: ...
@overload
def __getitem__(self, k: int) -> _T: ...
@overload
def __getitem__(self, k: str) -> Any: ...
@overload
def __getitem__(self, k: slice) -> QuerySet[_T]: ...
def __and__(self, other: QuerySet) -> QuerySet: ...
def __or__(self, other: QuerySet) -> QuerySet: ...
def iterator(self, chunk_size: int = ...) -> Iterator[_T]: ...
def aggregate(self, *args: Any, **kwargs: Any) -> Dict[str, Any]: ...
def get(self, *args: Any, **kwargs: Any) -> _T: ...
def get(self, *args: Any, **kwargs: Any) -> _Row: ...
def create(self, **kwargs: Any) -> _T: ...
def bulk_create(self, objs: Iterable[Model], batch_size: Optional[int] = ...) -> List[_T]: ...
def get_or_create(self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any) -> Tuple[_T, bool]: ...
def update_or_create(
self, defaults: Optional[MutableMapping[str, Any]] = ..., **kwargs: Any
) -> Tuple[_T, bool]: ...
def earliest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ...
def latest(self, *fields: Any, field_name: Optional[Any] = ...) -> _T: ...
def first(self) -> Optional[_T]: ...
def last(self) -> Optional[_T]: ...
def earliest(self, *fields: Any, field_name: Optional[Any] = ...) -> _Row: ...
def latest(self, *fields: Any, field_name: Optional[Any] = ...) -> _Row: ...
def first(self) -> Optional[_Row]: ...
def last(self) -> Optional[_Row]: ...
def in_bulk(self, id_list: Iterable[Any] = ..., *, field_name: str = ...) -> Dict[Any, _T]: ...
def delete(self) -> Tuple[int, Dict[str, int]]: ...
def update(self, **kwargs: Any) -> int: ...
@@ -93,31 +94,30 @@ class QuerySet(Iterable[_T], Sized):
def raw(
self, raw_query: str, params: Any = ..., translations: Optional[Dict[str, str]] = ..., using: None = ...
) -> RawQuerySet: ...
def values(self, *fields: Union[str, Combinable], **expressions: Any) -> QuerySet: ...
def values_list(self, *fields: Union[str, Combinable], flat: bool = ..., named: bool = ...) -> QuerySet: ...
# @overload
# def values_list(self, *fields: Union[str, Combinable], named: Literal[True]) -> NamedValuesListIterable: ...
# @overload
# def values_list(self, *fields: Union[str, Combinable], flat: Literal[True]) -> FlatValuesListIterable: ...
# @overload
# def values_list(self, *fields: Union[str, Combinable]) -> ValuesListIterable: ...
def values(self, *fields: Union[str, Combinable], **expressions: Any) -> QuerySet[_T, Dict[str, Any]]: ...
@overload
def values_list(self, *fields: Union[str, Combinable], named: Literal[True]) -> QuerySet[_T, NamedTuple]: ...
@overload
def values_list(self, *fields: Union[str, Combinable], flat: Literal[True]) -> QuerySet[_T, Any]: ...
@overload
def values_list(self, *fields: Union[str, Combinable]) -> QuerySet[_T, Tuple]: ...
def dates(self, field_name: str, kind: str, order: str = ...) -> QuerySet: ...
def datetimes(self, field_name: str, kind: str, order: str = ..., tzinfo: None = ...) -> QuerySet: ...
def none(self) -> QuerySet[_T]: ...
def all(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) -> QuerySet[_T, _Row]: ...
def all(self) -> QuerySet[_T, _Row]: ...
def filter(self, *args: Any, **kwargs: Any) -> QuerySet[_T, _Row]: ...
def exclude(self, *args: Any, **kwargs: Any) -> QuerySet[_T, _Row]: ...
def complex_filter(self, filter_obj: Any) -> QuerySet[_T, _Row]: ...
def count(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 union(self, *other_qs: Any, all: bool = ...) -> QuerySet[_T, _Row]: ...
def intersection(self, *other_qs: Any) -> QuerySet[_T, _Row]: ...
def difference(self, *other_qs: Any) -> QuerySet[_T, _Row]: ...
def select_for_update(self, nowait: bool = ..., skip_locked: bool = ..., of: Tuple = ...) -> QuerySet: ...
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 order_by(self, *field_names: Any) -> QuerySet[_T]: ...
def distinct(self, *field_names: Any) -> QuerySet[_T]: ...
def select_related(self, *fields: Any) -> QuerySet[_T, _Row]: ...
def prefetch_related(self, *lookups: Any) -> QuerySet[_T, _Row]: ...
def annotate(self, *args: Any, **kwargs: Any) -> QuerySet[_T, _Row]: ...
def order_by(self, *field_names: Any) -> QuerySet[_T, _Row]: ...
def distinct(self, *field_names: Any) -> QuerySet[_T, _Row]: ...
def extra(
self,
select: Optional[Dict[str, Any]] = ...,
@@ -126,11 +126,11 @@ class QuerySet(Iterable[_T], Sized):
tables: Optional[List[str]] = ...,
order_by: Optional[Sequence[str]] = ...,
select_params: Optional[Sequence[Any]] = ...,
) -> QuerySet[_T]: ...
def reverse(self) -> QuerySet[_T]: ...
def defer(self, *fields: Any) -> QuerySet[_T]: ...
def only(self, *fields: Any) -> QuerySet[_T]: ...
def using(self, alias: Optional[str]) -> QuerySet[_T]: ...
) -> QuerySet[_T, _Row]: ...
def reverse(self) -> QuerySet[_T, _Row]: ...
def defer(self, *fields: Any) -> QuerySet[_T, _Row]: ...
def only(self, *fields: Any) -> QuerySet[_T, _Row]: ...
def using(self, alias: Optional[str]) -> QuerySet[_T, _Row]: ...
@property
def ordered(self) -> bool: ...
@property
@@ -159,7 +159,7 @@ class RawQuerySet(Iterable[_T], Sized):
@overload
def __getitem__(self, k: str) -> Any: ...
@overload
def __getitem__(self, k: slice) -> QuerySet[_T]: ...
def __getitem__(self, k: slice) -> QuerySet[_T, _Row]: ...
@property
def columns(self) -> List[str]: ...
@property
4 changes: 2 additions & 2 deletions django-stubs/shortcuts.pyi
Original file line number Diff line number Diff line change
@@ -31,6 +31,6 @@ def redirect(

_T = TypeVar("_T", bound=Model)

def get_object_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T]], *args: Any, **kwargs: Any) -> _T: ...
def get_list_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T]], *args: Any, **kwargs: Any) -> List[_T]: ...
def get_object_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T, _T]], *args: Any, **kwargs: Any) -> _T: ...
def get_list_or_404(klass: Union[Type[_T], Manager[_T], QuerySet[_T, _T]], *args: Any, **kwargs: Any) -> List[_T]: ...
def resolve_url(to: Union[Callable, Model, str], *args: Any, **kwargs: Any) -> str: ...
7 changes: 7 additions & 0 deletions test-data/typecheck/queryset.test
Original file line number Diff line number Diff line change
@@ -7,4 +7,11 @@ reveal_type(Blog.objects.in_bulk([1])) # E: Revealed type is 'builtins.dict[Any,
reveal_type(Blog.objects.in_bulk()) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'
reveal_type(Blog.objects.in_bulk(['beatles_blog'], field_name='slug')) # E: Revealed type is 'builtins.dict[Any, main.Blog*]'

reveal_type(Blog.objects.values()) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.dict[builtins.str, Any]]'
reveal_type(Blog.objects.values()[0]) # E: Revealed type is 'builtins.dict*[builtins.str, Any]'


reveal_type(Blog.objects.values_list('id', 'slug')) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, builtins.tuple[Any]]'
reveal_type(Blog.objects.values_list('id', flat=True)) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, Any]'
reveal_type(Blog.objects.values_list('id', named=True)) # E: Revealed type is 'django.db.models.query.QuerySet[main.Blog*, typing.NamedTuple]'
[out]