0

I have a weird situation (translation: I'm missing something obvious) where I have a ListView that renders fine when I iterate over each object in my queryset and yield, but returns 0 results when I just return the queryset.

class TestListView(ListView):
    model = Result
    context_object_name = 'results'
    template_name = 'cases/test_list2.html'
    def get_queryset(self):
        # Get latest results
        results = Result.objects.filter(canonical=True,  environment__config__in=['staging', 'production']).order_by('test__id', '-created_at').distinct('test__id').select_related('test', 'environment')

        # Return Queryset
        return results  # type <class 'django.db.models.query.QuerySet'>, returns 0 elements from view
        for result in results:
            yield result  # returns correct number of results, assuming above 'Return Queryset' line is commented out

What am I doing incorrectly?

cdm
  • 719
  • 2
  • 10
  • 22
  • That doesn't make any sense. Is this really your whole code? You must be consuming the queryset _somewhere_. – Selcuk Nov 18 '19 at 23:26
  • Your comment helped me out - removing the for loop from the after the return solved the issue. But now my question is why? – cdm Nov 18 '19 at 23:38
  • 1
    after you `return` in python, no further lines in the function will execute – Hymns For Disco Nov 18 '19 at 23:40
  • @HymnsForDisco That's not it. Python will still see the function as a generator and in this case the `return` statement will not actually return anything but simply stop iteration. See https://stackoverflow.com/questions/16780002/return-in-generator-together-with-yield-in-python-3-3 – Selcuk Nov 18 '19 at 23:43
  • In any case, what I said was true, statements following a `return` won't execute, whether its a generator or function. I thought maybe OP was not familiar with this as putting code after returning should be an obvious red flag – Hymns For Disco Nov 18 '19 at 23:50
  • @Hymns For Disco I initially started with the for loop, and once it was working inserted the `return` above it thinking the for loop wouldn't execute - but that doesn't seem accurate. – cdm Nov 19 '19 at 00:11
  • The for loop doesn't execute, that's accurate. But what has changed is that since you have both `return` and `yield`, when calling `get_queryset`, you will get returned a generator object, not the `results` object that you were hoping for. Also, since your generator has that return statement in it, it cannot even yield anything since the iteration is immediately stopped (return won't even yield the object that you tried to return). In the ListView, your get_queryset method should not be a generator, so make sure there are no `yield` statements. btw, you can post an answer on your own question – Hymns For Disco Nov 19 '19 at 00:16

1 Answers1

0

Removing the for loop after the return solved my problem:

class TestListView(ListView):
    model = Result
    context_object_name = 'results'
    template_name = 'cases/test_list2.html'
    def get_queryset(self):
        # Get latest results
        results = Result.objects.filter(canonical=True,  environment__config__in=['staging', 'production']).order_by('test__id', '-created_at').distinct('test__id').select_related('test', 'environment')

        # Return Queryset
        return results  # type <class 'django.db.models.query.QuerySet'>, returns 0 elements from view

Thanks @Hymns For Disco and @Selcuk

cdm
  • 719
  • 2
  • 10
  • 22