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

ValuesQuerySet is removed and not available #144

Closed
sobolevn opened this issue Aug 25, 2019 · 7 comments
Closed

ValuesQuerySet is removed and not available #144

sobolevn opened this issue Aug 25, 2019 · 7 comments
Labels
bug Something isn't working documentation

Comments

@sobolevn
Copy link
Member

I have tried to use ValuesQuerySet that is returned in:

def post_dates_by_author(author_id: int):
    """Returns published blog posts."""
    x = BlogPost.objects.filter(
        author__id=author_id,
    ).values_list('created_at', flat=True)
    reveal_type(x)
    return x

Reproduction link: https://github.com/sobolevn/django_stubs_example/blob/master/server/apps/main/logic/repo.py

Output:

» PYTHONPATH="$PYTHONPATH:$PWD" mypy server
server/apps/main/logic/repo.py:20: note: Revealed type is 'django.db.models.query.ValuesQuerySet[server.apps.main.models.BlogPost, datetime.datetime]'

But, it looks like ValuesQuerySet is removed in 1.9, and there's not such class: https://github.com/django/django/blob/aed89adad54a977829c4f180b036033e031ebcc7/docs/releases/1.9.txt#L1069

So, it is not clear how to annotate your function to return ValuesQuerySet when it is missing from django.

@sobolevn sobolevn added the bug Something isn't working label Aug 25, 2019
@mkurnikov
Copy link
Member

I meant it to be stubs-only class, maybe I should've start it with _ or smth. Anyway, I haven't thought about the annotation of the return value...
Is it possible to annotate it with the string based annotation, like 'ValuesQuerySet'? Will mypy be ok with that?

If it's not, then I guess the only way is to go back to the multi-parameter generics then... Support of the annotate() will require third generic param, and it's very unobvious to the users.

@sobolevn
Copy link
Member Author

That's my attempt:

import typing

if typing.TYPE_CHECKING:
    from django.db.models.query import ValuesQuerySet

def test() -> 'ValuesQuerySet[BlogPost]':
    return BlogPost.objects.all().values_list('id', flat=True)

Output:

» PYTHONPATH="$PYTHONPATH:$PWD" mypy server
server/apps/main/logic/repo.py:19: error: "ValuesQuerySet" expects 2 type arguments, but 1 given

I was not sure about the second argument. And I have tried int:

def test() -> 'ValuesQuerySet[BlogPost, int]':
    return BlogPost.objects.all().values_list('id', flat=True)

And it worked.

@mkurnikov
Copy link
Member

mkurnikov commented Aug 26, 2019

Yes, this is kind of what I expected users to be doing. I wanted to make QuerySet a single argument type, as it's a most common case, and for other ones provide a special kinds of queryset classes.

Actually, for your case, in the wild, if you're going to return values_list from the function, it's probably going to be a Collection[...], not a QuerySet[...], and it will work with ValuesQuerySet without additional import. But if you do want to return values_list as QuerySet, it's case specific enough to spend some time learning how to do it.

We do need to add some docs for it, though.

@PetrDlouhy
Copy link

I have get away with this code in my case:

if typing.TYPE_CHECKING:
    from django.db.models.query import ValuesQuerySet
else:
    from typing import Dict as ValuesQuerySet
ENUM_CHOICES: ValuesQuerySet[AssetType, Tuple[str, str]] = AssetType.objects.values_list("name", "value")

But I consider it a very dirty hack.

@nunesvictor
Copy link

nunesvictor commented May 2, 2023

I tried with

from django.db import Model
from typing import Any, Dict, TypeAlias

ValuesQuerySet: TypeAlias[Model, Dict[str, Any]] = Dict

Is workings as expected for now, donno if is the best alternative but it's checking the argument types

@mschoettle
Copy link
Contributor

I found ValuesQuerySet in django_stubs_ext.aliases:

ValuesQuerySet = _QuerySet[_T, _Row]

Using that the following works:

from django_stubs_ext.aliases import ValuesQuerySet

def foo() -> ValuesQuerySet[MyModel, dict[str, Any]]:
    return MyModel.objects.values('field_one', 'field_two', 'another_field')

voidus added a commit to voidus/django-stubs that referenced this issue Apr 23, 2024
@intgr
Copy link
Collaborator

intgr commented May 29, 2024

Indeed as @mschoettle mentions, this has been solved for a long time, it has been publicly exported from django_stubs_ext.

And ValuesQuerySet is now being deprecated in favor of QuerySet[T, U].

@intgr intgr closed this as completed May 29, 2024
kalekseev pushed a commit to kalekseev/django-stubs that referenced this issue Jun 19, 2024
…ypeddjango#236)

Closes typeddjango#144

This seems straightforward, but I'm not writing a lot of .pyi files. I have tested it briefly and it seems to work.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working documentation
Development

No branches or pull requests

6 participants