Branch: master
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
80 lines (68 sloc) 3.17 KB
from astroid import MANAGER, nodes, InferenceError, inference_tip, UseInferenceDefault
from astroid.nodes import ClassDef, Attribute
from pylint_django.utils import node_is_subclass
def is_foreignkey_in_class(node):
# is this of the form field = models.ForeignKey
if not isinstance(node.parent, nodes.Assign):
return False
if not isinstance(node.parent.parent, ClassDef):
return False
if isinstance(node.func, Attribute):
attr = node.func.attrname
elif isinstance(node.func, nodes.Name):
attr =
return False
return attr in ('OneToOneField', 'ForeignKey')
def infer_key_classes(node, context=None):
for arg in node.args:
# typically the class of the foreign key will
# be the first argument, so we'll go from left to right
if isinstance(arg, (nodes.Name, nodes.Attribute)):
key_cls = None
for inferred in arg.infer(context=context):
key_cls = inferred
except InferenceError:
if key_cls is not None:
elif isinstance(arg, nodes.Const):
# can be 'Model' or 'app.Model'
module_name, _, model_name = arg.value.rpartition('.')
except AttributeError:
# when ForeignKey is specified only by class name we assume that
# this class must be found in the current module
if not module_name:
current_module = node.frame()
while not isinstance(current_module, nodes.Module):
current_module = current_module.parent.frame()
module_name =
elif not module_name.endswith('models'):
# otherwise Django allows specifying an app name first, e.g.
# ForeignKey('auth.User') so we try to convert that to
# 'auth.models', 'User' which works nicely with the `endswith()`
# comparison below
module_name += '.models'
for module in MANAGER.astroid_cache.values():
# only load model classes from modules which match the module in
# which *we think* they are defined. This will prevent infering
# other models of the same name which are found elsewhere!
if model_name in module.locals and
class_defs = [
module_node for module_node in module.lookup(model_name)[1]
if isinstance(module_node, nodes.ClassDef)
and node_is_subclass(module_node, 'django.db.models.base.Model')
if class_defs:
return iter([class_defs[0].instantiate_class()])
raise UseInferenceDefault
return iter([key_cls.instantiate_class()])
def add_transform(manager):
manager.register_transform(nodes.Call, inference_tip(infer_key_classes),