Repository: django/django
File: tests/custom_lookups/tests.py (Python)

Code before:

class CustomEndsWith(EndsWith):
    lookup_name = "ew"


class RelatedMoreThan(RelatedGreaterThan):
    lookup_name = "rmt"


class LookupTests(TestCase):
    def test_custom_name_lookup(self):
        a1 = Author.objects.create(name="a1", birthdate=date(1981, 2, 16))
        Author.objects.create(name="a2", birthdate=date(2012, 2, 29))
        with (
            register_lookup(models.DateField, YearTransform),
            register_lookup(models.DateField, YearTransform, lookup_name="justtheyear"),
            register_lookup(YearTransform, Exactly),
            register_lookup(YearTransform, Exactly, lookup_name="isactually"),
        ):
            qs1 = Author.objects.filter(birthdate__testyear__exactly=1981)
            qs2 = Author.objects.filter(birthdate__justtheyear__isactually=1981)
            self.assertSequenceEqual(qs1, [a1])
            self.assertSequenceEqual(qs2, [a1])

    def test_custom_exact_lookup_none_rhs(self):
        """
        __exact=None is transformed to __isnull=True if a custom lookup class
        with lookup_name != 'exact' is registered as the `exact` lookup.
        """
        field = Author._meta.get_field("birthdate")
        OldExactLookup = field.get_lookup("exact")
        author = Author.objects.create(name="author", birthdate=None)
        try:
            field.register_lookup(Exactly, "exact")
            self.assertEqual(Author.objects.get(birthdate__exact=None), author)
        finally:
            field.register_lookup(OldExactLookup, "exact")

    def test_basic_lookup(self):
        a1 = Author.objects.create(name="a1", age=1)
        a2 = Author.objects.create(name="a2", age=2)
        a3 = Author.objects.create(name="a3", age=3)
        a4 = Author.objects.create(name="a4", age=4)
        with register_lookup(models.IntegerField, Div3Lookup):
            self.assertSequenceEqual(Author.objects.filter(age__div3=0), [a3])
            self.assertSequenceEqual(
                Author.objects.filter(age__div3=1).order_by("age"), [a1, a4]
            )
            self.assertSequenceEqual(Author.objects.filter(age__div3=2), [a2])
            self.assertSequenceEqual(Author.objects.filter(age__div3=3), [])


Review comment (suggestion):
I like that `NotEqual` is now in our test suite, I checked the documented custom `AbsoluteValueLessThan` lookup that's in the docs and this also appears to be working :+1: 

Code after:


class CustomEndsWith(EndsWith):
    lookup_name = "ew"


class RelatedMoreThan(RelatedGreaterThan):
    lookup_name = "rmt"


class LookupTests(TestCase):
    def test_custom_name_lookup(self):
        a1 = Author.objects.create(name="a1", birthdate=date(1981, 2, 16))
        Author.objects.create(name="a2", birthdate=date(2012, 2, 29))
        with (
            register_lookup(models.DateField, YearTransform),
            register_lookup(models.DateField, YearTransform, lookup_name="justtheyear"),
            register_lookup(YearTransform, Exactly),
            register_lookup(YearTransform, Exactly, lookup_name="isactually"),
        ):
            qs1 = Author.objects.filter(birthdate__testyear__exactly=1981)
            qs2 = Author.objects.filter(birthdate__justtheyear__isactually=1981)
            self.assertSequenceEqual(qs1, [a1])
            self.assertSequenceEqual(qs2, [a1])

    def test_custom_lookup_with_subquery(self):
        class NotEqual(models.Lookup):
            lookup_name = "ne"

            def as_sql(self, compiler, connection):
                lhs, lhs_params = self.process_lhs(compiler, connection)
                rhs, rhs_params = self.process_rhs(compiler, connection)
                # Although combining via (*lhs_params, *rhs_params) would be
                # more resilient, the "simple" way works too.
                params = lhs_params + rhs_params
                return "%s <> %s" % (lhs, rhs), params

        author = Author.objects.create(name="Isabella")

        with register_lookup(models.Field, NotEqual):
            qs = Author.objects.annotate(
                unknown_age=models.Subquery(
                    Author.objects.filter(age__isnull=True)
                    .order_by("name")
                    .values("name")[:1]
                )
            ).filter(unknown_age__ne="Plato")
            self.assertSequenceEqual(qs, [author])

            qs = Author.objects.annotate(
                unknown_age=Lower(