Reputation:
I have models as shown below,
class Manufacturer(models.Model):
name = models.CharField(max_length=100)
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
name = models.CharField(max_length=300)
@property
def latest_variant(self):
return self.carvariant_set.last()
class CarVariant(models.Model):
car = models.ForeignKey(Car, on_delete=models.CASCADE)
name = models.CharField(max_length=300)
and I am making a query to get the latest variant of all cars, I am getting much duplicated queries.
I couldn't eliminate it with prefetch_related
Car.objects.all().prefetch_related('carvariant_set')
How can I eliminate the duplicated queries?
Upvotes: 3
Views: 393
Reputation: 477308
If you use .prefetch_related
it will populate the carvariant_set
value, but only for a .all()
query, not for a .last()
, that will trigger a new query.
What we can do is define a property like:
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
name = models.CharField(max_length=300)
@property
def latest_variant(self):
items = getattr(self, '_latest_variants', ())
if items:
return items[-1]
return self.carvariant_set.last()
Then we can prefetch the related object with:
from django.db.models import Prefetch
Car.objects.prefetch_related(
Prefetch(
'carvariant_set',
queryset=CarVariant.objects.order_by('pk'),
to_attr='_latest_variants'
)
)
Upvotes: 3
Reputation: 321
To get rid of duplicates you use "distinct()". For example Car.objects.all().prefetch_related('carvariant_set').distinct(). You can read about it here: https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.distinct
sometimes you might need to tell the "distinct" function which fields make an object distinct. By default it's the id, but you can do something like "distinct('name')" in order to avoid getting 2 instances with the same name for example.
Upvotes: 0