我正在使用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())
我想按相关性排序结果(例如,在艺术家名称匹配之前显示标题匹配)。
据我了解,这通常是通过使用anateate()完成的:设置排名编号,然后由order_by()使用。但是,我不确定使用Q对象时如何执行此操作。是否可以“注释” Q对象?还是我在这里树错树了?
答案 0 :(得分:2)
您应该能够使用Case语句执行此操作。用reduce构造Q对象有点丑陋,但一般的想法应该适用。 Link to the docs
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'
)