From 86ac419f327fc46c1d0b197950dbb9710df7ee25 Mon Sep 17 00:00:00 2001 From: fadedDexofan Date: Wed, 17 Apr 2019 11:05:30 +1000 Subject: [PATCH] Fixes #208 Support recursive (self) ForeignKey relations --- .../tests/input/func_noerror_foreignkeys.py | 11 ++++++++++ pylint_django/transforms/foreignkey.py | 21 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pylint_django/tests/input/func_noerror_foreignkeys.py b/pylint_django/tests/input/func_noerror_foreignkeys.py index ff77c044..fbfab16f 100644 --- a/pylint_django/tests/input/func_noerror_foreignkeys.py +++ b/pylint_django/tests/input/func_noerror_foreignkeys.py @@ -55,6 +55,17 @@ def get_username(self): return self.user.username +class Human(models.Model): + child = ForeignKey('self', on_delete=models.SET_NULL, null=True) + parent = ForeignKey(to='self', on_delete=models.SET_NULL, null=True) + + def get_grandchild(self): + return self.child.child + + def get_grandparent(self): + return self.parent.parent + + class UserPreferences(models.Model): """ Used for testing FK which refers to another model by diff --git a/pylint_django/transforms/foreignkey.py b/pylint_django/transforms/foreignkey.py index e69ae252..4df9c12f 100644 --- a/pylint_django/transforms/foreignkey.py +++ b/pylint_django/transforms/foreignkey.py @@ -1,6 +1,9 @@ from itertools import chain -from astroid import MANAGER, nodes, InferenceError, inference_tip, UseInferenceDefault +from astroid import ( + MANAGER, nodes, InferenceError, inference_tip, + UseInferenceDefault +) from astroid.nodes import ClassDef, Attribute from pylint_django.utils import node_is_subclass @@ -42,8 +45,20 @@ def infer_key_classes(node, context=None): break elif isinstance(arg, nodes.Const): try: - # can be 'Model' or 'app.Model' - module_name, _, model_name = arg.value.rpartition('.') + # can be 'self , 'Model' or 'app.Model' + if arg.value == 'self': + module_name = '' + # for relations with `to` first parent be Keyword(arg='to') + # and we need to go deeper in parent tree to get model name + if ( + isinstance(arg.parent, nodes.Keyword) + and arg.parent.arg == 'to' + ): + model_name = arg.parent.parent.parent.parent.name + else: + model_name = arg.parent.parent.parent.name + else: + module_name, _, model_name = arg.value.rpartition('.') except AttributeError: break