Как ранжировать результаты запроса при использовании объектов Q - PullRequest
0 голосов
/ 15 февраля 2019

Я создаю базу данных изображений, используя Django.Пользователь должен иметь возможность искать художественное произведение, используя его название, имена художников, его местоположение и т. Д. В настоящее время я использую Q Objects для построения запроса:

query_search = request.GET.get('search')
terms = [term.strip() for term in query_search.split()]
q_objects = Q()

for term in terms:
    q_objects.add(Q(title__icontains=term), Q.OR)
    artists = Artist.objects.filter(Q(name__istartswith=term) | Q(name__icontains=' ' + term))
    q_objects.add(Q(artists__in=artists), Q.OR)
    q_objects.add(Q(location_of_creation__name__istartswith=term), Q.OR)
    keywords = Keyword.objects.filter(name__icontains=term)
    q_objects.add(Q(keywords__in=keywords), Q.OR)

querysetList = (Artwork.objects.filter(q_objects)
                               .exclude(published=False)
                               .order_by('title',
                                         'location_of_creation',
                                         'artists')
                               .distinct())

Я хотел бы заказатьрезультаты по релевантности (например, показывать совпадения названий перед совпадениями имен исполнителей).

Насколько я понимаю, это обычно достигается с помощью annotate (): устанавливается рейтинговый номер изатем используется order_by ().Тем не менее, я не уверен, как это сделать при использовании объектов Q.Можно ли «аннотировать» объекты Q?Или я здесь не тот лай?

1 Ответ

0 голосов
/ 15 февраля 2019

Вы должны быть в состоянии сделать это с помощью операторов Case.Построение объектов Q с помощью Reduce немного уродливо, но общая идея должна применяться. Ссылка на документы

Artwork.objects.annotate(
    rank=Case(
        When(reduce(operator.or_, (Q(title__icontains=term) for term in terms)), then=Value(1)),
        When(reduce(operator.or_, (Q(location_of_creation__name__istartswith=term) for term in terms)), then=Value(2)),
        default=Value(99),
        output_field=IntegerField(),
    )
).order_by(
    'rank',
    'title',
    'location_of_creation',
    'artists'
)
...