33

I have a ListView in Django whose get_queryset() method will sometimes need to return no results. I've tried three ways to do this:

  1. return EmptyQuerySet()
  2. return Model.objects.none()
  3. return Model.objects.filter(pk=-1)

Each one of these returns a slightly different object.

  1. django.db.models.query.EmptyQuerySet with its model attribute set to None
  2. django.db.models.query.EmptyQuerySet with its model attribute set to Model
  3. django.db.models.query.QuerySet with its model attribute set to Model

Only the third option works with the class based ListView. The other options crash on an attribute error when the ListView tries to access the model attribute. This surprises me and is a pain as it requires me to import Model in places where that can cause MRO issues.

What am I doing wrong/what should I be doing differently?

Update: The question then is, what is the right way to return an empty queryset via the class view method get_queryset()?

Update: Here is the line in Django's generic views that hits an attribute error when trying access the model attribute: https://github.com/django/django/blob/stable/1.5.x/django/views/generic/list.py#L166.

ivanleoncz
  • 9,070
  • 7
  • 57
  • 49
Erik
  • 7,479
  • 8
  • 62
  • 99
  • Why can't you use the second option, `EmptyQuerySet` has a model attribute in that case. – Akshar Raaj Apr 28 '13 at 05:35
  • Just thinking about it makes me think you've got the wrong logic setup if you need to have an empty queryset in a listview. You should be able to handle that without a crash or so. – Henrik Andersson Apr 28 '13 at 06:08
  • @akshar: you would think, but Django still throws an Attribute error on this line: https://github.com/django/django/blob/stable/1.5.x/django/views/generic/list.py#L166 – Erik Apr 28 '13 at 15:31
  • @limelights: Having a list view with 0 items is a perfectly reasonable result. Customer x has 0 orders for example. – Erik Apr 28 '13 at 15:33
  • Of course, but that shouldnt be an empty queryset. It should be handled by the template. – Henrik Andersson Apr 28 '13 at 16:28
  • @limelights: not sure we are talking about the same thing. I don't believe Django's ListView should crash if my get_queryset() method returns an EmptyQuerySet() or a Model.objects.none() response. – Erik Apr 28 '13 at 16:41
  • What does MRO mean in this context? – Bash Mar 05 '20 at 20:49

1 Answers1

78

I think the best way to accomplish this is to call none() on objects for your respective model, and return the result. Assuming your model is named Entry:

queryset = Entry.objects.none()
Harel
  • 1,177
  • 10
  • 8
  • 4
    Why is this the preferred method when compared to the other methods that the author asks about? – Bash Mar 05 '20 at 20:51
  • 5
    @SebastianGaweda "Calling none() will create a queryset that never returns any objects and no query will be executed when accessing the results." Cause its fast cause it doesnt hit the DB – run_the_race Sep 02 '21 at 11:11
  • `.union` not working with this approach – Fathy Oct 09 '22 at 14:17