Django 摆脱嵌套模型中的重复查询

Django get rid of duplicated queries in nested models

我有如下图的模型,

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)

我正在查询以获取所有汽车的最新型号,但我收到了很多重复的查询。 我无法用 prefetch_related

消除它
Car.objects.all().prefetch_related('carvariant_set')

如何消除重复查询?

如果您使用 .prefetch_related,它将填充 carvariant_set 值,但仅适用于 .all() 查询,而不适用于 .last(),这将触发新查询.

我们可以做的是定义一个 属性 像:

class Car(models.Model):
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.CASCADE)
    name = models.CharField(max_length=300)
    
    @property
    def latest_variant(self):
        <strong>items</strong> = getattr(self, '_latest_variants', ())
        if items:
            return <strong>items[-1]</strong>
        return self.carvariant_set.last()

然后我们可以预取相关对象:

from django.db.models import <strong>Prefetch</strong>

Car.objects.prefetch_related(
    <strong>Prefetch(</strong>
        'carvariant_set',
        queryset=CarVariant.objects.order_by('pk'),
        to_attr='_latest_variants'
    <strong>)</strong>
)

要删除重复项,您可以使用“distinct()”。 例如 Car.objects.all().prefetch_related('carvariant_set').distinct()。你可以在这里读到它: https://docs.djangoproject.com/en/3.2/ref/models/querysets/#django.db.models.query.QuerySet.distinct

有时您可能需要告诉“distinct”函数哪些字段使对象不同。默认情况下它是 id,但您可以执行类似“distinct('name')”的操作以避免获得 2 个具有相同名称的实例。