在Django的ORM中 必須注意由於QuerySet的 cache導致的數據獲取不正確的問題
在哪些情況下不會出發QuerySet緩存?
隱式存儲QuerySet(查詢語句沒有顯示賦值給變量而直接進行遍歷或截取)
>>> from project.models import ProjectModel
>>>
>>> print([project_instance.name for project_instance in ProjectModel.objects.all()])
['first-test', 'test百度', 'project002']
>>> ProjectModel.objects.filter(name="project002").update(name="project003")
1
>>> print([project_instance.name for project_instance in ProjectModel.objects.all()])
['first-test', 'test百度', 'project003']
而顯示的存儲QuerSet 並且經過完整遍歷才會觸發緩存
完整遍歷的情況
>>> projects_queryset = ProjectModel.objects.all()
>>> print([project_instance for project_instance in projects_queryset]) # 完整遍歷
[<ProjectModel: first-test>, <ProjectModel: test百度>, <ProjectModel: project007>]
>>> ProjectModel.objects.filter(name="project007").update(name="project008")
1
>>> projects_queryset[1:3]
[<ProjectModel: test百度>, <ProjectModel: project007>] # project007還是緩存的老數據
不遍歷的情況
>>> projects_queryset = ProjectModel.objects.all()
>>> projects_queryset
<QuerySet [<ProjectModel: first-test>, <ProjectModel: test百度>, <ProjectModel: project008>]>
>>> ProjectModel.objects.filter(name="project008").update(name="project009")
1
>>> projects_queryset[1:3]
<QuerySet [<ProjectModel: test百度>, <ProjectModel: project009>]> # 沒拿緩存 project009
還有一種場景 也是需要注意的:
獲取到單個QuerySet對象后 通過objects update方法修改了部分字段值,此時的QuerySet還是緩存數據
>>> projects_obj = ProjectModel.objects.filter(name="project0011").first()
>>> projects_obj.name
'project0011'
>>> ProjectModel.objects.filter(name="project0011").update(name="project0012")
1
>>> projects_obj.name
'project0011'
有兩種方法可以解決這個問題
- 使用save修改
>>> projects_obj = ProjectModel.objects.filter(name="project0012").first()
>>> projects_obj.name
'project0012'
>>> projects_obj.name = "project0013"
>>> projects_obj.save()
>>> projects_obj.name
'project0013'
- 使用refresh_from_db()
>>> projects_obj = ProjectModel.objects.filter(name="project0013").first()
>>> projects_obj.name
'project0013'
>>> ProjectModel.objects.filter(name="project0013").update(name="project0014")
1
>>> projects_obj.refresh_from_db()
>>> projects_obj.name
'project0014'