简体   繁体   English

返回Django Queryset顶部的完全匹配

[英]Return exact matches at top of Django Queryset

I have a django model, called "User" which stores some basic information about people, namely first and last name. 我有一个django模型,称为“用户”,它存储一些关于人的基本信息,即名字和姓氏。 I currently have a simple search across my django model where, if a user types in a first name, The django queryset returns the first 10 matches, ordered by last name. 我现在有在我的Django模型一个简单的搜索,其中,如果用户键入的名字 ,查询集返回前10场比赛Django的,按姓氏排序。

For example, currently, if you search for "Sam" you might get the following results: 例如,目前,如果您搜索“Sam”,您可能会得到以下结果:

  1. Sam Abbott Sam Abbott
  2. Samuel Baker 塞缪尔贝克
  3. Sammy Rogers 萨米罗杰斯
  4. Sam Simmons 山姆西蒙斯

The code for this is simple: 这个代码很简单:

User.objects.filter(Q(first__istartswith=token)).order_by('last')

However, I want to alter this so that any exact first name matches are returned first, followed by the rest of the results. 但是,我想改变它,以便首先返回任何确切的名字匹配,然后是其余的结果。 So if someone types in "Sam", the results should instead be: 因此,如果有人输入“Sam”,结果应该是:

  1. Sam Abbott Sam Abbott
  2. Sam Simmons 山姆西蒙斯
  3. Samuel Baker 塞缪尔贝克
  4. Sammy Rogers 萨米罗杰斯

(Exact first name matches first, sorted by last name, followed by the rest of the matches sorted by last name). (确切的名字首先匹配,按姓氏排序,然后是按姓氏排序的其余匹配)。

I thought about turning this into 2 querysets and then just combining the lists, but I was wondering if it was possible to do this in 1 query, ideally sticking with the basic django queryset API (rather than writing a one-off query). 我想把它变成2个查询集然后只是组合列表,但我想知道是否有可能在1个查询中执行此操作,理想情况下坚持使用基本的django查询集API(而不是编写一次性查询)。 Does anyone know a way to do that? 有谁知道这样做的方法?

Thanks in advance. 提前致谢。

I don't think it's really possible to do that with only one query (at least with Django ORM). 我不认为只用一个查询(至少使用Django ORM)就可以做到这一点。

So your 2 queries should look like this: 所以你的2个查询应如下所示:

limit = 10
q1 = User.objects.filter(first__iexact=token).order_by('last')[:limit]
limit -= len(q1)
if limit:
    q2 = User.objects.exclude(pk__in=q1).filter(first__istartswith=token).order_by('last')[:limit]
else:
    q2 = []
users = list(q1) + list(q2)

Another way to do it is to filter the query in python but you will have to get all the results, not only the last 10: 另一种方法是在python中过滤查询,但你必须获得所有结果,而不仅仅是最后10个:

query = User.objects.filter(first__istartswith=token).order_by('last')
exacts = [user for user in query if user.first == token]
others = [user for user in query if user.first != token]
users = exacts + others
# Get exact matches first
qs1 = User.objects.filter(first__iexact=token).order_by('last')

# get secondary results second
qs2 = User.objects.filter(first__istartswith=token).exclude(qs1).order_by('last')

result = itertools.chain(qs1, qs2)

also take a look at this question which goes inot more depth than you probably need: How to combine 2 or more querysets in a Django view? 还要看看这个比你可能需要更深入的问题: 如何在Django视图中组合2个或更多的查询集?

It is not pretty and personally I would recommend using a search engine such as django-haystack but, if you know what database you are using you could use QuerySet.extra to add a field to order the records: 它不漂亮,我个人推荐使用django-haystack等搜索引擎,但是,如果你知道你使用的是什么数据库,你可以使用QuerySet.extra添加一个字段来订购记录:

extra = {'is_exact': "%s.first LIKE '%s'" % (User._meta.db_table, token)}
User.objects.filter(Q(first__istartswith=token)).extra(select=extra).order_by('-is_exact', 'last')

I think you might actually need full text search to accomplish that. 我认为您可能实际上需要全文搜索来实现这一目标。 Check out djang-sphinx . 看看djang-sphinx

If your example is as complicated as your full use case, you could just handle the sorting and ordering in your user code. 如果您的示例与完整用例一样复杂,您只需处理用户代码中的排序和排序即可。

You can order by multiple attributes. 您可以按多个属性订购。

User.objects.filter(Q(first__istartswith=token)).order_by('first', 'last')

So you order first by first so your objects get filters according to exact match and subsequent matches. 因此,您首先first订购,以便您的对象根据完全匹配和后续匹配获得过滤器。 And then you order again on last to sort according to last name. 然后你再次下令last按姓氏排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM