Răsfoiți Sursa

Fixed #29804 -- Added 'did you mean' suggestions for unsupported lookup error.

Abhinav Patil 6 ani în urmă
părinte
comite
bf01994a5c
3 a modificat fișierele cu 26 adăugiri și 3 ștergeri
  1. 1 0
      AUTHORS
  2. 9 2
      django/db/models/sql/query.py
  3. 16 1
      tests/lookup/tests.py

+ 1 - 0
AUTHORS

@@ -9,6 +9,7 @@ answer newbie questions, and generally made Django that much better:
     Aaron Swartz <http://www.aaronsw.com/>
     Aaron Swartz <http://www.aaronsw.com/>
     Aaron T. Myers <atmyers@gmail.com>
     Aaron T. Myers <atmyers@gmail.com>
     Abeer Upadhyay <ab.esquarer@gmail.com>
     Abeer Upadhyay <ab.esquarer@gmail.com>
+    Abhinav Patil <https://github.com/ubadub/>
     Abhishek Gautam <abhishekg1128@yahoo.com>
     Abhishek Gautam <abhishekg1128@yahoo.com>
     Adam Bogdał <adam@bogdal.pl>
     Adam Bogdał <adam@bogdal.pl>
     Adam Donaghy
     Adam Donaghy

+ 9 - 2
django/db/models/sql/query.py

@@ -6,6 +6,7 @@ themselves do not have to (and could be backed by things other than SQL
 databases). The abstraction barrier only works one way: this module has to know
 databases). The abstraction barrier only works one way: this module has to know
 all about the internals of models in order to get the information it needs.
 all about the internals of models in order to get the information it needs.
 """
 """
+import difflib
 import functools
 import functools
 from collections import Counter, OrderedDict, namedtuple
 from collections import Counter, OrderedDict, namedtuple
 from collections.abc import Iterator, Mapping
 from collections.abc import Iterator, Mapping
@@ -1140,10 +1141,16 @@ class Query:
         if transform_class:
         if transform_class:
             return transform_class(lhs)
             return transform_class(lhs)
         else:
         else:
+            output_field = lhs.output_field.__class__
+            suggested_lookups = difflib.get_close_matches(name, output_field.get_lookups())
+            if suggested_lookups:
+                suggestion = ', perhaps you meant %s?' % ' or '.join(suggested_lookups)
+            else:
+                suggestion = '.'
             raise FieldError(
             raise FieldError(
                 "Unsupported lookup '%s' for %s or join on the field not "
                 "Unsupported lookup '%s' for %s or join on the field not "
-                "permitted." %
+                "permitted%s" % (name, output_field.__name__, suggestion)
-                (name, lhs.output_field.__class__.__name__))
+            )
 
 
     def build_filter(self, filter_expr, branch_negated=False, current_negated=False,
     def build_filter(self, filter_expr, branch_negated=False, current_negated=False,
                      can_reuse=None, allow_joins=True, split_subq=True,
                      can_reuse=None, allow_joins=True, split_subq=True,

+ 16 - 1
tests/lookup/tests.py

@@ -569,13 +569,28 @@ class LookupTests(TestCase):
         ):
         ):
             Article.objects.filter(pub_date_year='2005').count()
             Article.objects.filter(pub_date_year='2005').count()
 
 
+    def test_unsupported_lookups(self):
         with self.assertRaisesMessage(
         with self.assertRaisesMessage(
             FieldError,
             FieldError,
             "Unsupported lookup 'starts' for CharField or join on the field "
             "Unsupported lookup 'starts' for CharField or join on the field "
-            "not permitted."
+            "not permitted, perhaps you meant startswith or istartswith?"
         ):
         ):
             Article.objects.filter(headline__starts='Article')
             Article.objects.filter(headline__starts='Article')
 
 
+        with self.assertRaisesMessage(
+            FieldError,
+            "Unsupported lookup 'is_null' for DateTimeField or join on the field "
+            "not permitted, perhaps you meant isnull?"
+        ):
+            Article.objects.filter(pub_date__is_null=True)
+
+        with self.assertRaisesMessage(
+            FieldError,
+            "Unsupported lookup 'gobbledygook' for DateTimeField or join on the field "
+            "not permitted."
+        ):
+            Article.objects.filter(pub_date__gobbledygook='blahblah')
+
     def test_relation_nested_lookup_error(self):
     def test_relation_nested_lookup_error(self):
         # An invalid nested lookup on a related field raises a useful error.
         # An invalid nested lookup on a related field raises a useful error.
         msg = 'Related Field got invalid lookup: editor'
         msg = 'Related Field got invalid lookup: editor'