根据我的代码库:

class City(models.Model):
    name = models.CharField(max_length=100)
    ...

class District(models.Model):
    city = models.ForeignKey(City, on_delete=models.CASCADE)

class Park(models.Model):
    district = models.ForeignKey(District, on_delete=models.CASCADE, related_name="parks")

class Plant(models.Model):
    name = models.CharField(max_length=200)
    plant_type = models.CharField(max_length=200)
    park = models.ForeignKey(Park, on_delete=models.CASCADE, related_name="plants")

def plants_of_type_in_park(plant_type, park):
    return park.plants.filter(plant_type=plant_type)

def generate_garden_report():
    report_data = {}
    plant_types = ["rose", "tulip", "daisy", ...etc]
    districts = District.objects.all()
    districts = districts.prefetch_related("parks", "parks__plants")
    for dist in districts.all():
        for park in districts.parks.all():
            for plant in plant_types:
                report_data[dist.city.name][plant] += plants_of_type_in_park(plant, park).count()
    return report_data

我的目标是使用预取来优化generate_garden_report函数.我加了districts.prefetch_related("parks", "parks__plants").但是,由于plants_of_type_in_park使用筛选器,因此它会触发另一个查询.我的方法是预取每个过滤器:

districts = districts.prefetch_related("parks", "parks__plants")
for plant in plant_types:
    districts = districts.prefetch_related(Prefetch("parks_plants", queryset=Plant.objects.filter(plant_type=plant)))

但是,由于parks_plants只能分配一次,所以我不能为此创建多个筛选器.我的目标是在对plants_of_type_in_park函数影响最小的情况下预取所需的一切,因为它在代码库的其他地方使用.

推荐答案

为了进一步提高性能,您可以使用每种植物类型的计数来注释公园,然后直接访问它们.

下面是一个例子:

def generate_garden_report():
    report_data = defaultdict(lambda: defaultdict(int))
    plant_types = ["rose", "tulip", "daisy"]
    districts = District.objects.prefetch_related(
        Prefetch(
            'parks',
            queryset=Park.objects.annotate(
                **{plant_type: Count('plants', filter=Q(plants__plant_type=plant_type)) for plant_type in plant_types}
            )
        )
    )

    for dist in districts:
        city_name = dist.city.name
        for park in dist.parks.all():
            for plant_type in plant_types:
                report_data[city_name][plant_type] += getattr(park, plant_type, 0)
    return report_data

Django相关问答推荐

如何在django模板中渲染标签集

Django REST framework:object has no attributed after annotation;Got attributeError when try to get a value for field field on serializer<>

Django-无法显示基于字段值的元素

如何在Django上创建ManyToMany管理面板?

Django modelform在包含在另一个模板中时不呈现

django re_path() 函数模式与包含该模式的 url 不匹配

Django多对多关系报错:<title> object (None)>需要先设置id字段的值.

在 Django 4.1 中提交表单之前显示数据

如何在 Django 模板中的计数器上进行 for 循环中断?

所有子元素的Django自递归外键过滤器查询

恢复 Django 1.7 RemoveField 迁移

Django - 强制执行 ManyToManyField 唯一项

将网络测功机添加到 Heroku django 应用程序时如何克服Coudn't find that formation错误?

relation "django_site" does not exist

django - pisa:将图像添加到 PDF 输出

CherryPy 与 Django

如何创建一个在复选框右侧显示复选框标签的 Django 表单?

javascript 文件中的 Django {% static 'path' %}

如何过滤(或替换)在 UTF-8 中占用超过 3 个字节的 unicode 字符?

Django:如何从模板中识别调用视图?