首页 > 解决方案 > 在 Django ListView 中更新 get_queryset 后如何更改排序?

问题描述

我有一个列表视图,在其中实现了搜索栏功能,但似乎我的排序现在不起作用。我该如何解决?我希望能够在方法之后以我想要的方式订购列表get_queryset..

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

标签: pythondjango

解决方案


如果您查看 ListView 的源代码,您会看到这样的类。

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

在您的代码中,您将覆盖 get_ordering() 以提供您想要的排序。但是您还覆盖了调用 get_ordering() 的 get_queryset() 方法。如果您没有覆盖 get_queryset() 方法,您的排序将被默认的 get_queryset() 方法接受。但是由于您要覆盖 get_queryset() 方法,因此您已明确使用 get_ordering() 方法。

通过做这样的事情来改变你的 get_queryset() 。

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

推荐阅读