0
# QuerySet Type Aliases
1
2
Specialized type aliases for Django QuerySets that provide better type safety and IDE support when working with query results and values() calls. These aliases adapt their behavior based on whether type checking is active.
3
4
## Capabilities
5
6
### Generic QuerySet Alias
7
8
A flexible QuerySet type alias that works with any model type, providing proper generic support for type checkers while maintaining runtime compatibility.
9
10
```python { .api }
11
QuerySetAny = QuerySet
12
"""
13
Type alias for generic QuerySet with any model.
14
15
In TYPE_CHECKING mode: Resolves to _QuerySetAny from django-stubs
16
At runtime: Standard Django QuerySet class
17
"""
18
```
19
20
### Values QuerySet Alias
21
22
Specialized QuerySet type for handling values() query results with proper row typing support.
23
24
```python { .api }
25
ValuesQuerySet = QuerySet
26
"""
27
Type alias for QuerySet with values() calls.
28
29
In TYPE_CHECKING mode: Resolves to _QuerySet[_T, _Row] from django-stubs
30
At runtime: Standard Django QuerySet class
31
"""
32
```
33
34
### Usage Examples
35
36
Basic QuerySet typing:
37
38
```python
39
from django_stubs_ext import QuerySetAny
40
from django.db import models
41
42
class User(models.Model):
43
name = models.CharField(max_length=100)
44
email = models.EmailField()
45
46
# Type-safe QuerySet operations
47
def get_users() -> QuerySetAny:
48
return User.objects.all()
49
50
users: QuerySetAny = get_users()
51
active_users: QuerySetAny = users.filter(is_active=True)
52
```
53
54
Values QuerySet typing:
55
56
```python
57
from django_stubs_ext import ValuesQuerySet
58
from django.db import models
59
60
class Product(models.Model):
61
name = models.CharField(max_length=100)
62
price = models.DecimalField(max_digits=10, decimal_places=2)
63
64
# Type-safe values() operations
65
def get_product_summaries() -> ValuesQuerySet:
66
return Product.objects.values('name', 'price')
67
68
summaries: ValuesQuerySet = get_product_summaries()
69
for summary in summaries:
70
# Type checker understands this is a dict-like row
71
print(f"{summary['name']}: ${summary['price']}")
72
```
73
74
### Type Checking Behavior
75
76
The aliases provide different behavior in static analysis vs runtime:
77
78
```python
79
import typing
80
from django.db.models.query import QuerySet
81
82
if typing.TYPE_CHECKING:
83
# Static type checking mode
84
from django.db.models.query import _QuerySetAny, _QuerySet, _Row, _T
85
86
QuerySetAny = _QuerySetAny
87
ValuesQuerySet = _QuerySet[_T, _Row]
88
else:
89
# Runtime mode
90
QuerySetAny = QuerySet
91
ValuesQuerySet = QuerySet
92
```
93
94
This dual behavior ensures compatibility with both type checkers (which use the django-stubs type definitions) and runtime execution (which uses the actual Django QuerySet class).
95
96
### Integration with Django ORM
97
98
These aliases work seamlessly with Django's ORM methods:
99
100
```python
101
from django_stubs_ext import QuerySetAny, ValuesQuerySet
102
from django.db import models
103
from typing import Optional
104
105
class BlogPost(models.Model):
106
title = models.CharField(max_length=200)
107
content = models.TextField()
108
published = models.BooleanField(default=False)
109
110
def search_posts(query: str) -> QuerySetAny:
111
"""Search for published blog posts."""
112
return BlogPost.objects.filter(
113
title__icontains=query,
114
published=True
115
)
116
117
def get_post_titles() -> ValuesQuerySet:
118
"""Get just the titles of published posts."""
119
return BlogPost.objects.filter(published=True).values('title')
120
121
# Type-safe usage
122
results: QuerySetAny = search_posts("django")
123
first_post: Optional[BlogPost] = results.first()
124
125
titles: ValuesQuerySet = get_post_titles()
126
title_list: list = list(titles)
127
```
128
129
## Types
130
131
```python { .api }
132
import typing
133
from django.db.models.query import QuerySet
134
135
if typing.TYPE_CHECKING:
136
from django.db.models.query import _QuerySetAny, _QuerySet, _Row, _T
137
138
QuerySetAny = _QuerySetAny
139
ValuesQuerySet = _QuerySet[_T, _Row]
140
else:
141
QuerySetAny = QuerySet
142
ValuesQuerySet = QuerySet
143
```