【问题标题】:How to custom sort a Django queryset如何自定义排序 Django 查询集
【发布时间】:2012-09-22 13:46:21
【问题描述】:

给定一个带有标题字符串的数据模型,比如说:

class DVD(models.Model):
    title = models.CharField(max_length=100)
class DVDAdmin(admin.ModelAdmin):
    ordering = ('title',)

sample_titles = {"A Fish Called Wanda", "The Good, the Bad, and the Unsorted",
                 "A River Runs Upstream", "The Incredibles",}

我想生成一个按标题排序的查询集,但将标题视为减去列表中的任何前导词,例如 ("a", "an", "the",)。因此,“超人特工队”将排在“河流上游”等之前。我不想只是 截断 数据,无论是在数据库中还是在结果视图中。我想为查询集创建一个内部自定义排序。

似乎可能可行的一种方法是创建一个自定义更改列表,然后在那里对查询集进行排序,如下所示:

from django.contrib.admin.views.main import Changelist
class title_sortlist(Changelist):
    def apply_special_ordering(self, queryset):
        qs_desc = self.models.objects.all().order_by('-title')
        return qs_desc
    def get_query_set(self, request, *args, **kwargs):
        queryset = super(title_sortlist, self).get_query_set(request)
        queryset = self.apply_special_ordering(queryset)
        return queryset

class DVDAdmin(admin.ModelAdmin):
    ordering = ('title',)
    def get_changelist(self, request, **kwargs):
        return title_sortlist

这适用于标准排序 - 降序排序会覆盖模型的升序排序。但是,我还没有弄清楚如何获取查询集并对其进行自定义排序。

另一种可能性可能是动态向模型添加一个字段,将其命名为cut_title,进行适当编辑,然后按该字段排序。但是,我刚刚开始阅读有关动态模型更改的内容,还不清楚如何去做(更不用说,它似乎有点不稳定,比常规的猴子修补更严重)。

第三个选项,我读到 Django 有一个用于查询集的 extra 选项,您可以在其中添加其他 SQL,包括新字段。不过,我不知道如何添加一个代表已编辑标题的新 SQL 字段 - 也许 Django SQL 可以调用 Python 函数?

那么,如果有的话,哪种方法最适合按(修改的)标题对查询集进行排序?

【问题讨论】:

  • @bebraw,可能相关,但不是解决方案 - sorted 方法显然不返回查询集。
  • 是的。这是有问题的。我希望有人知道更好的方法。不幸的是,根据接受的答案,没有后端不可知的方式来执行这类查询。
  • 嗯。刚刚有了一个可能可行但略显粗糙的想法。复制数据(即没有 The 等的存储标题)并将其用于排序。有效,但男人很丑。

标签: python django django-queryset


【解决方案1】:

cmets 中的@bebraw 其实是对的。

创建一个特殊的排序字段就是这样做的。这也是 SOLR 等搜索框架的自定义。您甚至可以应用特殊的文本分析来根据语言进行排序。

在您的情况下,如果就像删除停用词(文章的简短列表)一样简单,您将创建一个常规模型字段,从另一个字段复制数据并删除停用词。

使用常规数据库字段的好处:您可以创建数据库索引(例如,在 UPPER(value) 上)并能够对数据库索引支持的不区分大小写进行排序(您必须使用 QuerySet 添加一个额外的字段。额外按 UPPER(value)) 排序。

这将允许快速排序和分页的结果。如果你在 Django 中做所有事情,你将不得不检索整个数据。对于数百行来说,这可能足够快,但如果数据增加,则根本无法扩展。

但是: 根据您的数据小心停用词。停用词的反例是标题“To Be or Not To Be”,它完全由您可能很容易归类为停用词的内容组成,并且在通过这样的过滤器时会简单地被消灭。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-20
    • 2019-05-19
    • 2016-08-28
    • 2020-07-19
    • 1970-01-01
    • 2011-11-29
    • 2013-09-26
    • 2016-11-30
    相关资源
    最近更新 更多