-
Notifications
You must be signed in to change notification settings - Fork 117
/
Copy pathqueryset_iterator.py
41 lines (33 loc) · 1.42 KB
/
queryset_iterator.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
from astroid.nodes import Attribute, Call
from pylint import checkers
from pylint.checkers import utils
from pylint_django.__pkginfo__ import BASE_ID
# from pylint_django.augmentations import is_manager_attribute
class QuerysetIteratorForLoopChecker(checkers.BaseChecker):
"""
Checks for usage of "QuerySet.all()" in the head of a for loop,
eventually suggesting the usage of ".iterator()"
"""
name = "queryset-iterator-forloop-checker"
msgs = {
f"R{BASE_ID}07": (
"Consider using 'Queryset.iterator()'",
"consider-using-queryset-iterator",
"Using 'QuerySet.all()' may load all results in memory "
"if you need to iterate over the data only once and don't need "
"caching, 'QuerySet.iterator()' may be a more performant option.",
),
}
@utils.only_required_for_messages("consider-using-queryset-iterator")
def visit_for(self, node):
"""
Checks for a QuerySet.all() inside of a for loop
May create false positives
"""
for subnode in node.get_children():
if isinstance(subnode, Call):
if isinstance(subnode.func, Attribute):
# Ensure it's an attribute, to avoid clashing with the
# all() python builtin
if subnode.func.attrname == "all":
self.add_message(f"R{BASE_ID}07", node=subnode)