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

issue while trying to use with_cte on EmptyResultSet #84

Open
afpekmezci opened this issue Dec 11, 2023 · 1 comment · May be fixed by #92
Open

issue while trying to use with_cte on EmptyResultSet #84

afpekmezci opened this issue Dec 11, 2023 · 1 comment · May be fixed by #92

Comments

@afpekmezci
Copy link

afpekmezci commented Dec 11, 2023

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__
@millerdev
Copy link
Contributor

This sounds similar to #64

Maybe there is a similar workaround here as for that?

@camuthig camuthig linked a pull request May 17, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants