Given these models:
class Listing(models.Model):
features = models.ManyToManyField('Feature', related_name='listing_details')
comments = models.TextField()
class Feature(models.Model):
feature = models.CharField(max_length=100, unique=True)
How do I do a full-text search for Listing
s with text in either comments or one of the related Feature
s?
I tried this:
In[28]: Listing.objects.annotate(search=SearchVector('comments', 'features__feature')).filter(search='something').count()
Out[28]:
1215
So, I know not all those records contain the text something
.
However, the number is "right" in the sense that a regular non-full-text query comes up with the same number:
In[33]: Listing.objects.filter(Q(comments__icontains='something') | Q(features__feature__icontains='something')).count()
Out[33]:
1215
I can get down to just the Listing
objects containing the text something
in the comments
field or in features__feature
like so:
In[34]: Listing.objects.filter(Q(comments__icontains='something') | Q(features__feature__icontains='something')).distinct().count()
Out[34]:
25
The real question boils down to how do I get those same 25 records back with full text search?
I used ManyToManyField in SearchVector with StringAgg to avoid strange duplication and have correct results.
In your example the correct query should be:
from django.contrib.postgres.aggregates import StringAgg
from django.contrib.postgres.search import SearchVector
Listing.objects.annotate(
search=SearchVector('comments') + SearchVector(StringAgg('features__feature', delimiter=' '))
).filter(search='something')
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With