Django在遍历查询集时,何时读取数据库?
Posted
技术标签:
【中文标题】Django在遍历查询集时,何时读取数据库?【英文标题】:Django when looping over a queryset, when does the db read happen? 【发布时间】:2018-09-25 08:53:35 【问题描述】:我正在循环访问我的数据库并更新我的所有 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
,是否仍会被此循环访问?如果我为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()
【问题讨论】:
这段代码是在视图内、芹菜任务内还是其他地方执行? 这段代码是从manage.py shell
开始的
【参考方案1】:
Company.objects.filter(updated=False)
转换为普通的 SQL 查询:
SELECT * FROM appName_company WHERE updated is false
当您开始遍历 Company
对象时,将执行此 SQL 查询。它只执行一次。第二台服务器将无法识别第一台服务器的工作,因为它们都将通过相同的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,但锁可能会减慢数据库速度。
【讨论】:
select_for_update()
在 SQLite 上被忽略:docs.djangoproject.com/en/2.1/ref/databases/… 另见:***.com/a/46949541/1097104以上是关于Django在遍历查询集时,何时读取数据库?的主要内容,如果未能解决你的问题,请参考以下文章
如何在返回的 AJAX 调用上使用 django 模板标签?