如何使用Django ORM有效地迭代许多外键对象



假设我有model,比如:

class User(AbstractUser):
...
seller = models.ForeignKey(Seller, related_name="user", on_delete=models.SET_NULL, null=True)
...

我试图使用以下代码获取seller电子邮件地址:

from app.models import User
from django_print_sql import print_sql
with print_sql(count_only=False):
users = User.objects.filter(is_active=True, seller_id__isnull=False).select_related().only('seller__email')
for u in users.iterator():
email = u.seller.email
send_email(email)

在这种情况下,我可以看到SQL查询,如:

SELECT `user`.`id`,
`user`.`seller_id`
FROM `user`
WHERE (`user`.`is_active`
AND `user`.`seller_id` IS NOT NULL)
...
SELECT `seller`.`id`,
...
`seller`.`email`,
...
FROM `seller`
WHERE `seller`.`id` = 1
...

问题是Django ORM在每次迭代(Select seller... where seller.id = ...(时访问DB。因此,如果我们有很多卖家,那将是太多的查询(==DB连接(。

换句话说,可以用values:代替only

from app.models import User
from django_print_sql import print_sql
with print_sql(count_only=False):
users = User.objects.filter(is_active=True, seller_id__isnull=False).select_related().values('seller__email')
for u in users.iterator():
email = u['seller__email']
send_email(email)

我可以看到SQL查询,比如:

SELECT `seller`.`email`
FROM `user`
INNER JOIN `seller` ON (`user`.`seller_id` = `seller`.`id`)
WHERE (`user`.`is_active`
AND `user`.`seller_id` IS NOT NULL)

它稍微好一点,我们可以通过单个DB查询来获取电子邮件,但iterator在这里是无用的,因为我们在dict对象中加载所有电子邮件一次,整个数据都存在于内存中。

问题是
在不创建限制User.objects.filter查询计数的手动子循环的情况下,是否可以按数据块进行迭代(比如按500封电子邮件/单个查询(?换句话说,在这种情况下,什么是最有效的迭代器?

在您的情况下,您没有为select_related提供参数,我建议您将seller字段设置为select_related,如下所示:

from app.models import User
from django_print_sql import print_sql
with print_sql(count_only=False):
users = User.objects.select_related('seller').filter(is_active=True, seller_id__isnull=False).only('seller__email')
for u in users.iterator():
email = u.seller.email
send_email(email)

将CCD_ 12置于CCD_ 13管理器之前。通过这样做,django将卖家模型记录作为每个迭代用户的字段,并且不会在每次迭代中访问数据库。

看起来select_related适用于这种情况:

from app.models import User
from django_print_sql import print_sql
with print_sql(count_only=False):
users = User.objects.filter(is_active=True, seller_id__isnull=False).select_related('seller').only('seller__email').exclude(seller__email__exact='')
for u in users.iterator():
send_email(u.seller.email)
SELECT `user`.`id`,
`user`.`owner_id`,
`seller`.`id`,
`seller`.`email`
FROM `user`
INNER JOIN `seller` ON (`user`.`seller_id` = `seller`.`id`)
WHERE (`user`.`is_active`
AND `user`.`seller_id` IS NOT NULL
AND NOT (`seller`.`email` =
AND `seller`.`email` IS NOT NULL))

相关内容

  • 没有找到相关文章

最新更新