Use get_queryset() method or set queryset variable?
Asked Answered
G

5

69

These two pieces of code are identical at the first blush:

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_poll_list'
    queryset = Poll.active.order_by('-pub_date')[:5]

and

class IndexView(generic.ListView):
    template_name = 'polls/index.html'
    context_object_name = 'latest_poll_list'

    def get_queryset(self):
        return Poll.active.order_by('-pub_date')[:5]

Is there any difference between them? And if it is:

What approach is better? Or when setting queryset variable is better than override the get_queryset method? And vice versa.

Goatskin answered 31/10, 2013 at 13:1 Comment(0)
I
104

In your example, overriding queryset and get_queryset have the same effect. I would slightly favour setting queryset because it's less verbose.

When you set queryset, the queryset is created only once, when you start your server. On the other hand, the get_queryset method is called for every request.

That means that get_queryset is useful if you want to adjust the query dynamically. For example, you could return objects that belong to the current user:

class IndexView(generic.ListView):
    def get_queryset(self):
        """Returns Polls that belong to the current user"""
        return Poll.active.filter(user=self.request.user).order_by('-pub_date')[:5]

Another example where get_queryset is useful is when you want to filter based on a callable, for example, return today's polls:

class IndexView(generic.ListView):
    def get_queryset(self):
        """Returns Polls that were created today"""
        return Poll.active.filter(pub_date=date.today())

If you tried to do the same thing by setting queryset, then date.today() would only be called once, when the view was loaded, and the view would display incorrect results after a while.

class IndexView(generic.ListView):
    # don't do this!
    queryset = Poll.active.filter(pub_date=date.today())
Ieper answered 31/10, 2013 at 13:29 Comment(1)
you can also write in get_queryset self.model.objects.filter(...). In case of inheriting own listviews it is worth to remember that one should refer to super(YourListViewExtendingSomeOtherLV, self).get_queryset().filter(...)Craquelure
I
14

Other answers have missed an important implication of the fact that the queryset attribute is evaluated when the process starts. Because you aren't just creating a queryset, you're actually slicing it, the query will be evaluated at that point. That means that you will only ever get the top 5 polls at that moment, and they won't refresh even if you create another one, until the process is restarted.

This is exactly when you should be using get_queryset().

Intact answered 31/10, 2013 at 17:41 Comment(2)
According to the docs, slicing an unevaluated queryset won't cause it to be evaluated unless you use the 'step' parameter of the slice syntax.Ieper
This is not true, if you inserted a new recent entry into the database, it will appear. I just tested it, test it for yourself. If the query set was limited to be until timezone.now() for example, then yes you would never get any result after then when the program fired up (unless the program restarted). The query is run on request, but any terms within the query (e.g. timezone.now() are not re-evaluated, and will be the inital values).Investigate
C
4

The queryset attribute is used internally, always use the method (you will often have to perform custom queries based on request or session vars for example)

Coeternity answered 31/10, 2013 at 13:28 Comment(0)
A
3

Model and queryset are very similar, but queryset's value if provided overrides that of model's.

Model is what type of Object this view displays.

Overriding get_queryset controls what specific instances this view displays (ex: the last 5 instances created)

From Django's documentation:

model:

The model that this view will display data for. Specifying model = Foo is effectively the same as specifying queryset = Foo.objects.all(), where objects stands for Foo’s default manager.

queryset:

A QuerySet that represents the objects. If provided, the value of queryset supersedes the value provided for model.

get_queryset:

get_queryset() Returns the queryset that will be used to retrieve the object that this view will display. By default, get_queryset() returns the value of the queryset attribute if it is set, otherwise it constructs a QuerySet by calling the all() method on the model attribute’s default manager.

Acantho answered 21/10, 2017 at 14:10 Comment(0)
M
0

inside class just include

Class MyViewSet(GenericAPIView):

    queryset = ''

if you don't use the queryset anywhere.

This worked for me.

Thanks

Macrophage answered 27/4, 2018 at 6:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.