-
Notifications
You must be signed in to change notification settings - Fork 57
Closed
Description
Django has a built-in check when the rhs of the query should return an empty queryset. It raises an EmptyResultSet and returns an empty list for the result. When you combine an EmptyResultSet query with_cte unfortunately, django-cte does not recognize it, and throws an error instead of returning an empty list.
-- queryset -- <CTEQuerySet []>
cte.query
SELECT "population_cte"."id", "population_cte"."year", "population_cte"."population" FROM "population_cte" WHERE "population_cte"."population" <= 10000000
--POPULATIONS QUERY :
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/ahp/Desktop/cte_test/testapp/core/api.py", line 87, in empty_query_issue
print(
File "/Users/ahp/Desktop/cte_test/venv/lib/python3.9/site-packages/django/db/models/query.py", line 374, in __repr__
data = list(self[: REPR_OUTPUT_SIZE + 1])
File "/Users/ahp/Desktop/cte_test/venv/lib/python3.9/site-packages/django/db/models/query.py", line 398, in __iter__
self._fetch_all()
File "/Users/ahp/Desktop/cte_test/venv/lib/python3.9/site-packages/django/db/models/query.py", line 1881, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/Users/ahp/Desktop/cte_test/venv/lib/python3.9/site-packages/django/db/models/query.py", line 99, in __iter__
model_cls = klass_info["model"]
TypeError: 'NoneType' object is not subscriptable# simple model
from django.db import models
from django_cte import CTEManager
class Population(models.Model):
class Meta:
db_table = "population"
year = models.PositiveIntegerField()
population = models.BigIntegerField()
objects = CTEManager()
def __str__(self) -> str:
return f"{self.year} : {self.population}"# test function
def empty_query_issue():
queryset = Population.objects.filter(year__in=[])
# print(
# "--queryset.query \n",
# queryset.query,
# )
print(
"-- queryset",
f"-- {queryset}"
)
cte = With(
queryset,
name="population_cte",
)
cte_queryset = cte.queryset()
cte_queryset = cte_queryset.filter(population__lte=10000000)
print(
"cte.query \n",
cte_queryset.query,
)
populations = cte_queryset.with_cte(cte)
print(
'--POPULATIONS QUERY : \n',
populations,
)for a quick fix, you can overwrite the __iter__ method of the CTEQuerySet, but this is not a proper solution.
from django_cte import CTEQuerySet
from typing import Iterator
from django.core.exceptions import EmptyResultSet
class FixedCTEQuerySet(CTEQuerySet):
def __iter__(self) -> Iterator:
try:
return super(CTEQuerySet, self).__iter__()
except Exception:
try:
str(self.query)
except EmptyResultSet:
return iter([])
else:
raise
CTEQuerySet.__iter__ = FixedCTEQuerySet.__iter__Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels