Reputation: 118
I have two models with a one-to-many relation through a ForeignKey
. At some stage, I have obtained a queryset of the 'one' objects and would like to retrieve, as efficiently as possible, all of the 'many' objects that are associated with them. Here is a minimal example:
class Car(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=1000)
@classmethod
def search(cls, keyword):
return keyword_search_cars(cls, keyword)
class Passenger(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE)
Now I would like to query the models like so:
# Get all passengers in cars matching term 'truck'
cars = Car.search('truck')
passengers = cars.passenger_set.all() # Not permitted on querysets!
But the best I can come up with is something like this:
car_ids = Car.search('truck').values_list('id', flat=True)
passengers = Passenger.objects.filter(car_id__in=car_ids)
With hundreds of records in the cars
queryset, the __in
filter seems like a dumb way to query the database. According to the docs, this does not do a SQL JOIN
but instead writes a huge WHERE id IN (1, 2, 3, ... )
which does not seem optimal.
Does anyone know of a better approach for this? Currently my queries take 10+ seconds (with 1M+ records) which means rather poor performance for my application. It will get even slower as the database table grows in length.
For further context, the Cars.search
method here can be considered an abstraction for full-text search with the django.contrib.postgres.search
module (that's what my application is actually doing).
EDIT: show code for full text search method behind Car.search()
:
from django.contrib.postgres.search import (
SearchQuery,
SearchRank,
SearchVector,
)
RANK_THRESHOLD = 0.1
def keyword_search_cars(Model, query):
vector = (
SearchVector('name', weight='A')
+ SearchVector('description', weight='B')
)
query = SearchQuery(query)
cars_results = (
Model.objects.annotate(rank=SearchRank(vector, query))
.filter(rank__gte=RANK_THRESHOLD)
.order_by('-rank')
)
return cars_results
Upvotes: 0
Views: 93