|
70 | 70 |
|
71 | 71 | - case: queryset_method_of_union
|
72 | 72 | main: |
|
73 |
| - from typing_extensions import reveal_type |
| 73 | + from typing_extensions import TypedDict, reveal_type |
| 74 | + from django.contrib.auth.models import User |
| 75 | + from django.db import models |
74 | 76 | from myapp.models import MyModel1, MyModel2
|
75 | 77 | kls: type[MyModel1 | MyModel2] = MyModel1
|
| 78 | +
|
76 | 79 | reveal_type(kls.objects) # N: Revealed type is "django.db.models.manager.Manager[myapp.models.MyModel1] | django.db.models.manager.Manager[myapp.models.MyModel2]"
|
77 | 80 | reveal_type(kls.objects.all()) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, myapp.models.MyModel1] | django.db.models.query.QuerySet[myapp.models.MyModel2, myapp.models.MyModel2]"
|
78 | 81 | reveal_type(kls.objects.get()) # N: Revealed type is "myapp.models.MyModel1 | myapp.models.MyModel2"
|
| 82 | +
|
| 83 | + # Regular QuerySet |
| 84 | + foos = MyModel1.objects.all() |
| 85 | + bars = MyModel2.objects.all() |
| 86 | +
|
| 87 | + reveal_type(foos.union(bars)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, myapp.models.MyModel1]" |
| 88 | + reveal_type(foos.intersection(bars)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, myapp.models.MyModel1]" |
| 89 | + reveal_type(foos.difference(bars)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, myapp.models.MyModel1]" |
| 90 | +
|
| 91 | + # `values_list()` QuerySet |
| 92 | + foos_list = MyModel1.objects.all().values_list("name") |
| 93 | + bars_list = MyModel2.objects.all().values_list("name") |
| 94 | +
|
| 95 | + reveal_type(foos_list.union(bars_list)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, tuple[builtins.str]]" |
| 96 | + reveal_type(foos_list.intersection(bars_list)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, tuple[builtins.str]]" |
| 97 | + reveal_type(foos_list.difference(bars_list)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, tuple[builtins.str]]" |
| 98 | +
|
| 99 | + def union_values_list() -> models.QuerySet[models.Model, tuple[str]]: |
| 100 | + union = foos_list.union(bars_list) |
| 101 | + return union |
| 102 | +
|
| 103 | + # `values()` QuerySet -- One field, same name |
| 104 | + foos_dict = MyModel1.objects.all().values("name") |
| 105 | + bars_dict = MyModel2.objects.all().values("name") |
| 106 | +
|
| 107 | + reveal_type(foos_dict.union(bars_dict)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str})]" |
| 108 | + reveal_type(foos_dict.intersection(bars_dict)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str})]" |
| 109 | + reveal_type(foos_dict.difference(bars_dict)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str})]" |
| 110 | +
|
| 111 | + # `values()` QuerySet -- One field, different name, the first one takes precedence. |
| 112 | + # cf https://docs.djangoproject.com/en/5.2/ref/models/querysets/#django.db.models.query.QuerySet.union |
| 113 | + foos_dict2 = MyModel1.objects.all().values("name") |
| 114 | + bars_dict2 = MyModel2.objects.all().values("id") |
| 115 | +
|
| 116 | + reveal_type(foos_dict2.union(bars_dict2)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str})]" |
| 117 | + reveal_type(foos_dict2.intersection(bars_dict2)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str})]" |
| 118 | + reveal_type(foos_dict2.difference(bars_dict2)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str})]" |
| 119 | +
|
| 120 | + # `values()` QuerySet -- Multiple field, same names |
| 121 | + foos_dict3 = MyModel1.objects.all().values("name", "id") |
| 122 | + bars_dict3 = MyModel2.objects.all().values("name", "id") |
| 123 | +
|
| 124 | + reveal_type(foos_dict3.union(bars_dict3)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 125 | + reveal_type(foos_dict3.intersection(bars_dict3)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 126 | + reveal_type(foos_dict3.difference(bars_dict3)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 127 | +
|
| 128 | + # Mixing `values()` and `values_list()` is apparently ok and takes the type of the first queryset |
| 129 | + foos_dict4 = MyModel1.objects.all().values("name", "id") |
| 130 | + bars_list4 = MyModel2.objects.all().values_list("name", "id") |
| 131 | +
|
| 132 | + reveal_type(foos_dict4.union(bars_list4)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 133 | + reveal_type(foos_dict4.intersection(bars_list4)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 134 | + reveal_type(foos_dict4.difference(bars_list4)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 135 | +
|
| 136 | + # TODO: Should be an error (mixed number of selected columns) -- runtime raises 'The used SELECT statements have a different number of columns' |
| 137 | + foos_dict5 = MyModel1.objects.all().values("name", "id") |
| 138 | + bars_dict5 = MyModel2.objects.all().values("name") |
| 139 | +
|
| 140 | + reveal_type(foos_dict5.union(bars_dict5)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 141 | + reveal_type(foos_dict5.intersection(bars_dict5)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 142 | + reveal_type(foos_dict5.difference(bars_dict5)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel1, TypedDict({'name': builtins.str, 'id': builtins.int})]" |
| 143 | +
|
| 144 | + # TODO: Should be an error (mixed number of columns) -- runtime raises 'The used SELECT statements have a different number of columns' |
| 145 | + model2_qs = MyModel2.objects.all() |
| 146 | + user_qs = User.objects.all() |
| 147 | +
|
| 148 | + reveal_type(model2_qs.union(bars_dict5)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel2, myapp.models.MyModel2]" |
| 149 | + reveal_type(model2_qs.intersection(bars_dict5)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel2, myapp.models.MyModel2]" |
| 150 | + reveal_type(model2_qs.difference(bars_dict5)) # N: Revealed type is "django.db.models.query.QuerySet[myapp.models.MyModel2, myapp.models.MyModel2]" |
| 151 | +
|
| 152 | +
|
79 | 153 | installed_apps:
|
| 154 | + - django.contrib.auth |
80 | 155 | - myapp
|
81 | 156 | files:
|
82 | 157 | - path: myapp/__init__.py
|
83 | 158 | - path: myapp/models.py
|
84 | 159 | content: |
|
85 | 160 | from django.db import models
|
86 | 161 | class MyModel1(models.Model):
|
87 |
| - pass |
| 162 | + name = models.TextField(blank=False, null=False) |
88 | 163 | class MyModel2(models.Model):
|
89 |
| - pass |
| 164 | + name = models.TextField(blank=False, null=False) |
90 | 165 |
|
91 | 166 | - case: select_related_returns_queryset
|
92 | 167 | main: |
|
|
0 commit comments