Reputation: 2393
I have a list view in which I implemented a search bar feature but it seems that my ordering is now not working. How do I fix this? I would like to be able to order the list the way I want after the get_queryset
method..
class MemoListView(LoginRequiredMixin, ListView):
model = Memo
template_name = 'memos/memos.html'
context_object_name = 'memos'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['memo_list'] = Memo.objects.all()
return context
def get_ordering(self):
ordering = self.request.GET.get('ordering', '-date_time')
return ordering
def get_queryset(self):
query = self.request.GET.get('q')
if query:
memo_list = Memo.objects.filter(
Q(title__icontains=query) | Q(content__icontains=query))
else:
memo_list = Memo.objects.all()
return memo_list
Upvotes: 3
Views: 2704
Reputation: 1314
Alternatively, you can just add order_by
method to the line where you are making the query. So the return
line of the class will change to:
return memo_list.order_by('-date_time')
Upvotes: 1
Reputation: 1
you need to call the super get_queryset
function to get the get_ordering
funtion effective.
add this in your get_queryset()
function
queryset = super(IndexView, self).get_queryset()
Upvotes: 0
Reputation: 1304
If you take a look at the source code of ListView you'd see a class like this.
class MultipleObjectMixin(ContextMixin):
"""A mixin for views manipulating multiple objects."""
allow_empty = True
queryset = None
model = None
paginate_by = None
paginate_orphans = 0
context_object_name = None
paginator_class = Paginator
page_kwarg = 'page'
ordering = None
def get_queryset(self):
"""
Return the list of items for this view.
The return value must be an iterable and may be an instance of
` QuerySet` in which case `QuerySet` specific behavior will be enabled.
"""
if self.queryset is not None:
queryset = self.queryset
if isinstance(queryset, QuerySet):
queryset = queryset.all()
elif self.model is not None:
queryset = self.model._default_manager.all()
else:
raise ImproperlyConfigured(
"%(cls)s is missing a QuerySet. Define "
"%(cls)s.model, %(cls)s.queryset, or override "
"%(cls)s.get_queryset()." % {
'cls': self.__class__.__name__
}
)
ordering = self.get_ordering()
if ordering:
if isinstance(ordering, str):
ordering = (ordering,)
queryset = queryset.order_by(*ordering)
return queryset
def get_ordering(self):
"""Return the field or fields to use for ordering the queryset."""
return self.ordering
In your code, you are overriding get_ordering() to provide the ordering you want. But you are also overriding the get_queryset() method where the get_ordering() was called. If you did not override get_queryset() method your ordering would have been accepted by the default get_queryset() method. But since you're overriding the get_queryset() method you have use the get_ordering() method explicitly.
Change your get_queryset() by doing something like this.
def get_queryset(self):
query = self.request.GET.get('q')
if query:
memo_list = Memo.objects.filter(
Q(title__icontains=query) | Q(content__icontains=query))
else:
memo_list = Memo.objects.all()
ordering = self.get_ordering()
memo_list = memo_list.order_by(ordering)
# The following checks are not needed since your get_ordering() will always only return ONE string
# if ordering and isinstance(ordering, str):
# ordering = (ordering,)
# memo_list = memo_list.order_by(*ordering)
return memo_list
Upvotes: 5