Reputation: 4008
I have two models Item
and Owner
:
class Item(models.Model):
name = models.CharField(max_length=255)
owner = models.ForeignKey(
Owner, related_name='owner_items',
on_delete=models.CASCADE,
)
is_featured = models.BooleanField(
choices=CHOICES, default=BOOL_NO
)
# ...
I do a full-text search (based on Django docs) in the Item name and description fields. PostgreSQL version is 10.
search_vectors = (
SearchVector('name', weight='A', config='english') +
SearchVector('description', weight='B', config='english')
)
terms = [SearchQuery(term) for term in keyword.split()]
search_query = functools.reduce(operator.or_, terms)
search_rank = SearchRank(
search_vectors, search_query, weights=[0.2, 0.4, 0.6, 1]
)
qs = Item.objects.all().annotate(
rank=search_rank
).filter(rank__gte=0.2).order_by('-rank')
I want to introduce also the Owner
, name
field in the equation, also give a little boost to the rank if is_featured
is true
.
I have the Owner
instance model before doing this search.
Upvotes: 1
Views: 499
Reputation: 6122
You can add the field name
from class Owner
in the search_vector
, maybe with a different weight
and the same config
(it's only an hypothesis because you didn't specified the Owner model definition or data).
A way to use is_featured
as a boost for your rank
can be annotate a 1 (you can use other values) if it's True
and then add it to the SearchRank
result.
from django.db import models
from django.db.models import Case, Value, When
from django.contrib.postgres.search import (
SearchQuery, SearchRank, SearchVector,
)
search_vectors = (
SearchVector('name', weight='A', config='english') +
SearchVector('description', weight='B', config='english') +
SearchVector('owner__name', weight='C', config='english')
)
terms = [SearchQuery(term) for term in keyword.split()]
search_query = functools.reduce(operator.or_, terms)
search_rank = SearchRank(
search_vectors, search_query, weights=[0.2, 0.4, 0.6, 1]
)
qs = Item.objects.all().annotate(
featured_boost=Case(
When(is_featured=True, then=Value(1)),
default=Value(0),
output_field=models.IntegerField(),
)
).annotate(
rank=search_rank + featured_boost
).filter(rank__gte=0.2).order_by('-rank')
Upvotes: 2