diff --git a/django_filters/utils.py b/django_filters/utils.py index eaec56578..4f6f62690 100644 --- a/django_filters/utils.py +++ b/django_filters/utils.py @@ -174,7 +174,10 @@ def verbose_field_name(model, field_name): names = [] for part in parts: if isinstance(part, ForeignObjectRel): - names.append(part.related_name.replace('_', ' ')) + if part.related_name: + names.append(part.related_name.replace('_', ' ')) + else: + return '[invalid name]' else: names.append(force_text(part.verbose_name)) diff --git a/tests/test_utils.py b/tests/test_utils.py index 6bb69b8c4..a164b1f45 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -17,12 +17,16 @@ verbose_field_name, verbose_lookup_expr, label_for_filter, raw_validation, ) -from .models import User -from .models import Article -from .models import Book -from .models import HiredWorker -from .models import Business -from .models import NetworkSetting +from .models import ( + User, + Article, + Book, + HiredWorker, + Business, + NetworkSetting, + Company, + Account, +) class GetFieldPartsTests(TestCase): @@ -253,6 +257,26 @@ def test_lazy_text(self): verbose_name = verbose_field_name(User, 'username') self.assertEqual(verbose_name, 'username') + def test_forwards_fk(self): + verbose_name = verbose_field_name(Article, 'author') + self.assertEqual(verbose_name, 'author') + + def test_backwards_fk(self): + # https://github.com/carltongibson/django-filter/issues/716 + + # related_name is set + verbose_name = verbose_field_name(Company, 'locations') + self.assertEqual(verbose_name, 'locations') + + # related_name not set. Auto-generated relation is `article_set` + # _meta.get_field raises FieldDoesNotExist + verbose_name = verbose_field_name(User, 'article_set') + self.assertEqual(verbose_name, '[invalid name]') + + # WRONG NAME! Returns ManyToOneRel with related_name == None. + verbose_name = verbose_field_name(User, 'article') + self.assertEqual(verbose_name, '[invalid name]') + class VerboseLookupExprTests(TestCase):