【问题标题】:Django ORM orderby exact / prominent match to be on topDjango ORM orderby 精确/突出匹配位于顶部
【发布时间】:2018-03-06 00:13:38
【问题描述】:

我需要根据 Django ORM 中的匹配长度对结果进行排序。

我有一个Suburb 表,在name 字段中有位置详细信息。

我需要用给定的文本搜索表格,并按完全匹配/最突出的匹配排序为顶部

例如:

1) 如果搜索字符串是 'America',那么结果应该是 [America, South America, North America ..] 在这种情况下,我们找到了一个完全匹配,它必须是第一个元素。

2) 如果搜索是port,那么结果应该是['Port Melbourne' 'Portsea', East Airport]

在这种情况下,我们发现端口在分隔符之前是完全匹配的。

我知道我可以使用多个查询并加入它们,比如一个用于完全匹配,另一个用于部分匹配,然后在部分匹配时使用排除加入它们就像

search_list=  [x.name for x in Suburb.objects.filter(name=search)] 
# Then
search_list += [x.name for x in Suburb.objects.filter(name__iregex=r"[[:<:]]{0}".format(search)).exclude(name__in=search_list)]

我可以这样继续下去。但想知道我们是否有更好的方法。

有什么线索吗?

提前致谢

【问题讨论】:

  • 你使用哪个数据库?
  • 我正在使用 MySQL。通过使用 python,我得到了一个可行的解决方案。会尝试你的建议。不过我想在 ORM 中使用它

标签: python django django-queryset django-orm


【解决方案1】:

基于func

postgres 的解决方案(应该在 mysql 中工作,但不能测试):

from django.db.models import Func

class Position(Func):
    function = 'POSITION'
    arg_joiner = ' IN '

    def __init__(self, expression, substring):
        super(Position, self).__init__(substring, expression)


Suburb.objects.filter(
    name__icontains=search).annotate(
    pos=Position('name', search)).order_by('pos')

编辑:根据 Tim Graham 的修复,在 Django docs - Avoiding SQL injection 中推荐。

【讨论】:

  • 严重安全警报:清理搜索字符串。否则,此示例可能会受到 SQL 注入攻击。 (通过搜索字符串删除表进行验证。)
  • @hynekcer 能否展示一下攻击搜索字符串的示例。
  • 我建议使用名称和参数,例如来自 Django 2.0 alpha 1 的未来 django.db.models.functions.StrIndex docs 并复制并粘贴 django.db.models.functions.base.StrIndex
  • 你不想问一个问题如何编写更复杂的函数表达式?参数较多的函数的问题、局限和解决方法,体内嵌套函数,什么时候不能依赖自动转义?我认为这个问题可能会被高票、查看和评论,最后有人可以为 Django 文档写一个更短的 PR。上面的问题太宽泛了,与 Func 无关。其他问题类似“我正在尝试......(非常特别的事情)”,而不是一般答案的问题如何。 (由于用户 cmets 和编辑历史,SO 非常完美。)
【解决方案2】:

Django 2.0 实现一个函数

StrIndex(string, substring)

返回一个正整数,对应于字符串中第一次出现的子字符串的 1 索引位置,如果未找到子字符串,则返回 0。

例子:

from django.db.models.functions import StrIndex

qs = (
    Suburb.objects
    .filter(name__contains='America')
    .annotate(search_index=StrIndex('name', Value('America')))
)

【讨论】:

    猜你喜欢
    • 2016-06-23
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 2016-03-07
    • 2023-03-24
    • 1970-01-01
    • 2013-08-15
    • 1970-01-01
    相关资源
    最近更新 更多