Django 在查询集上循环时,数据库读取何时发生?

Django when looping over a queryset, when does the db read happen?

我正在遍历我的数据库并更新我所有的 Company 对象。

for company in Company.objects.filter(updated=False):
    driver.get(company.company_url)
    company.adress = driver.find_element_by_id("address").text
    company.visited = True    
    company.save()

我的问题是它花费的时间太长,所以我想 运行 同一代码的另一个实例,但我很好奇实际的数据库读取何时发生。如果company.visited get 改成了True,而这个循环是运行ning,这个循环还会访问吗?如果我为 visited 添加第二个检查怎么办?如果第一个实例无法识别第二个实例的工作,我不想开始第二个循环:

for company in Company.objects.filter(updated=False):
    if company.visited:
        continue
    driver.get(company.company_url)
    company.adress = driver.find_element_by_id("address").text
    company.visited = True    
    company.save()

Company.objects.filter(updated=False) 转换为普通的 SQL 查询:

SELECT * FROM appName_company WHERE updated is false

此 SQL 查询在您开始遍历 Company 个对象时执行。它只执行一次。第二个服务器将无法识别第一个服务器的工作,因为它们都将通过相同的 Company 个对象。

使用原子事务和select_for_update():

锁定行以避免竞争条件
from django.db import transaction

for company in Company.objects.filter(updated=False):
    with transaction.atomic():
        Company.objects.select_for_update().get(id=company.id)
        if company.visited:
            continue
        driver.get(company.company_url)
        company.adress = driver.find_element_by_id("address").text
        company.visited = True    
        company.save()

您可以 运行 在多个服务器上使用此代码。每个 Company 只处理一次。

如果你需要定期执行这段代码,我强烈推荐使用 Celery。每个公司分配一个任务,让多个工人并行工作:

from celery import shared_task

@shared_task
def dispatch_tasks():
    for company in Company.objects.filter(updated=False):
        process_company.delay(company.id)

@shared_task
@transaction.atomic
def process_company(company_id):
    company = Company.objects.select_for_update().get(id=company_id)
    if company.visited:
        continue
    driver.get(company.company_url)
    company.adress = driver.find_element_by_id("address").text
    company.visited = True    
    company.save()

编辑:哦,我看到你用 sqlite 标签标记了问题。我建议切换到 PostgreSQL,因为 SQLite 在并发性方面确实很差。我的答案应该适用于 SQlite,但锁可能会降低数据库速度。