[英]How to use "Prefetch()" with "filter()" to reduce `SELECT` queries to iterate 3 or more models?
I have Country
, State
and City
models which are chained by foreign keys as shown below:我有
Country
, State
和City
模型,它们由外键链接,如下所示:
class Country(models.Model):
name = models.CharField(max_length=20)
class State(models.Model):
country = models.ForeignKey(Country, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
class City(models.Model):
state = models.ForeignKey(State, on_delete=models.CASCADE)
name = models.CharField(max_length=20)
Then, when I iterate Country
, State
and City
models with prefetch_related() and all() as shown below:然后,当我使用prefetch_related()和all()迭代
Country
、 State
和City
模型时,如下所示:
# ↓ Here ↓
for country_obj in Country.objects.all().prefetch_related("state_set__city_set"):
for state_obj in country_obj.state_set.all(): # Here
for city_obj in state_obj.city_set.all(): # Here
print(country_obj, state_obj, city_obj)
3 SELECT
queries are run as shown below. 3
SELECT
查询运行如下所示。 *I use PostgreSQL and these below are the query logs of PostgreSQL and you can see this answer explaining how to enable and disable the query logs on PostgreSQL: *我使用 PostgreSQL 以下是 PostgreSQL 的查询日志,你可以看到这个解释如何启用和禁用 PostgreSQL 的查询日志的答案:
But, when I iterate with filter() instead of all()
as shown below:但是,当我使用filter()而不是
all()
进行迭代时,如下所示:
# Here
for country_obj in Country.objects.filter().prefetch_related("state_set__city_set"):
for state_obj in country_obj.state_set.filter(): # Here
for city_obj in state_obj.city_set.filter(): # Here
print(country_obj, state_obj, city_obj)
8 SELECT
queries are run as shown below instead of 3 SELECT
queries: 8
SELECT
查询运行如下所示,而不是 3 SELECT
查询:
So, I use Prefetch() with filter()
to reduce 8 SELECT
queries to 3 SELECT
queries as shown below:因此,我使用Prefetch()和
filter()
将 8 个SELECT
查询减少到 3 个SELECT
查询,如下所示:
for country_obj in Country.objects.filter().prefetch_related(
Prefetch('state_set', # Here
queryset=State.objects.filter(),
to_attr='state_obj'
),
Prefetch('city_set', # Here
queryset=City.objects.filter(),
to_attr='city_obj'
),
):
print(country_obj, country_obj.state_obj, country_obj.city_obj)
But, the error below occurs:但是,出现以下错误:
AttributeError: Cannot find 'city_set' on Country object, 'city_set' is an invalid parameter to prefetch_related()
AttributeError:在国家 object 上找不到“city_set”,“city_set”是 prefetch_related() 的无效参数
So, how can I use Prefetch()
with filter()
to reduce 8 SELECT
queries to 3 SELECT
queries?那么,我如何使用
Prefetch()
和filter()
将 8 个SELECT
查询减少到 3 个SELECT
查询?
Try nesting prefetch objects尝试嵌套预取对象
countries = Country.objects.filter().prefetch_related(
Prefetch('state_set', # Here
queryset=State.objects.filter().prefetch_related(
Prefetch("city_set",
queryset=City.objects.filter(),
),
),
)
Then run everything with all()
since it's already filtered然后使用
all()
运行所有内容,因为它已经被过滤
for country_obj in countries:
for state_obj in country_obj.state_set.all():
for city_obj in state_obj.city_set.all():
print(country_obj, state_obj, city_obj)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.