def test_expressions(self): author = Author.objects.annotate(backward=Reverse(Trim('name'))).get(pk=self.john.pk) self.assertEqual(author.backward, self.john.name[::-1]) with register_lookup(CharField, Reverse), register_lookup(CharField, Length): authors = Author.objects.all() self.assertCountEqual(authors.filter(name__reverse__length__gt=7), [self.john, self.elena]) self.assertCountEqual(authors.exclude(name__reverse__length__gt=7), [self.python])
def test_foreignobject_lookup_registration(self): field = Article._meta.get_field('author') with register_lookup(models.ForeignObject, Exactly): self.assertIs(field.get_lookup('exactly'), Exactly) # ForeignObject should ignore regular Field lookups with register_lookup(models.Field, Exactly): self.assertIsNone(field.get_lookup('exactly'))
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_transform_order_by(self): with register_lookup(models.IntegerField, LastDigitTransform): a1 = Author.objects.create(name='a1', age=11) a2 = Author.objects.create(name='a2', age=23) a3 = Author.objects.create(name='a3', age=32) a4 = Author.objects.create(name='a4', age=40) qs = Author.objects.order_by('age__lastdigit') self.assertSequenceEqual(qs, [a4, a1, a3, a2])
def test_subquery_usage(self): with register_lookup(models.IntegerField, Div3Transform): Author.objects.create(name='a1', age=1) a2 = Author.objects.create(name='a2', age=2) Author.objects.create(name='a3', age=3) Author.objects.create(name='a4', age=4) qs = Author.objects.order_by('name').filter(id__in=Author.objects.filter(age__div3=2)) self.assertSequenceEqual(qs, [a2])
def test_transform(self): query = Query(Author) with register_lookup(CharField, Lower): where = query.build_where(~Q(name__lower='foo')) lookup = where.children[0] self.assertIsInstance(lookup, Exact) self.assertIsInstance(lookup.lhs, Lower) self.assertIsInstance(lookup.lhs.lhs, SimpleCol) self.assertEqual(lookup.lhs.lhs.target, Author._meta.get_field('name'))
def test_transform(self): with register_lookup(CharField, Lower): Author.objects.create(name='John Smith', alias='smithj') Author.objects.create(name='Rhonda') authors = Author.objects.filter(name__lower__exact='john smith') self.assertQuerysetEqual( authors.order_by('name'), ['John Smith'], lambda a: a.name )
def test_ordering_allows_registered_lookups(self): class Model(models.Model): test = models.CharField(max_length=100) class Meta: ordering = ('test__lower',) with register_lookup(models.CharField, Lower): self.assertEqual(Model.check(), [])
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), [])
def test_bilateral_fexpr(self): with register_lookup(models.IntegerField, Mult3BilateralTransform): a1 = Author.objects.create(name='a1', age=1, average_rating=3.2) a2 = Author.objects.create(name='a2', age=2, average_rating=0.5) a3 = Author.objects.create(name='a3', age=3, average_rating=1.5) a4 = Author.objects.create(name='a4', age=4) baseqs = Author.objects.order_by('name') self.assertSequenceEqual(baseqs.filter(age__mult3=models.F('age')), [a1, a2, a3, a4]) # Same as age >= average_rating self.assertSequenceEqual(baseqs.filter(age__mult3__gte=models.F('average_rating')), [a2, a3])
def test_birthdate_month(self): a1 = Author.objects.create(name='a1', birthdate=date(1981, 2, 16)) a2 = Author.objects.create(name='a2', birthdate=date(2012, 2, 29)) a3 = Author.objects.create(name='a3', birthdate=date(2012, 1, 31)) a4 = Author.objects.create(name='a4', birthdate=date(2012, 3, 1)) with register_lookup(models.DateField, InMonth): self.assertSequenceEqual(Author.objects.filter(birthdate__inmonth=date(2012, 1, 15)), [a3]) self.assertSequenceEqual(Author.objects.filter(birthdate__inmonth=date(2012, 2, 1)), [a2]) self.assertSequenceEqual(Author.objects.filter(birthdate__inmonth=date(1981, 2, 28)), [a1]) self.assertSequenceEqual(Author.objects.filter(birthdate__inmonth=date(2012, 3, 12)), [a4]) self.assertSequenceEqual(Author.objects.filter(birthdate__inmonth=date(2012, 4, 1)), [])
def test_lookups_caching(self): field = Article._meta.get_field('author') # clear and re-cache field.get_lookups.cache_clear() self.assertNotIn('exactly', field.get_lookups()) # registration should bust the cache with register_lookup(models.ForeignObject, Exactly): # getting the lookups again should re-cache self.assertIn('exactly', field.get_lookups())
def test_bilateral_order(self): with register_lookup(models.IntegerField, Mult3BilateralTransform, Div3BilateralTransform): 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) baseqs = Author.objects.order_by('name') # mult3__div3 always leads to 0 self.assertSequenceEqual(baseqs.filter(age__mult3__div3=42), [a1, a2, a3, a4]) self.assertSequenceEqual(baseqs.filter(age__div3__mult3=42), [a3])
def test_partial_gin_index(self): with register_lookup(CharField, Length): index_name = 'char_field_gin_partial_idx' index = GinIndex(fields=['field'], name=index_name, condition=Q(field__length=40)) with connection.schema_editor() as editor: editor.add_index(CharFieldModel, index) constraints = self.get_constraints(CharFieldModel._meta.db_table) self.assertEqual(constraints[index_name]['type'], 'gin') with connection.schema_editor() as editor: editor.remove_index(CharFieldModel, index) self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table))
def test_bilateral_multi_value(self): with register_lookup(models.CharField, UpperBilateralTransform): Author.objects.bulk_create([ Author(name='Foo'), Author(name='Bar'), Author(name='Ray'), ]) self.assertQuerysetEqual( Author.objects.filter(name__upper__in=['foo', 'bar', 'doe']).order_by('name'), ['Bar', 'Foo'], lambda a: a.name )
def test_trim_transform(self): Author.objects.create(name=' John ') Author.objects.create(name='Rhonda') tests = ( (LTrim, 'John '), (RTrim, ' John'), (Trim, 'John'), ) for transform, trimmed_name in tests: with self.subTest(transform=transform): with register_lookup(CharField, transform): authors = Author.objects.filter(**{'name__%s' % transform.lookup_name: trimmed_name}) self.assertQuerysetEqual(authors, [' John '], lambda a: a.name)
def test_bilateral_upper(self): with register_lookup(models.CharField, UpperBilateralTransform): Author.objects.bulk_create([ Author(name='Doe'), Author(name='doe'), Author(name='Foo'), ]) self.assertQuerysetEqual( Author.objects.filter(name__upper='doe'), ["<Author: Doe>", "<Author: doe>"], ordered=False) self.assertQuerysetEqual( Author.objects.filter(name__upper__contains='f'), ["<Author: Foo>"], ordered=False)
def test_div3_bilateral_extract(self): with register_lookup(models.IntegerField, Div3BilateralTransform): 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) baseqs = Author.objects.order_by('name') self.assertSequenceEqual(baseqs.filter(age__div3=2), [a2]) self.assertSequenceEqual(baseqs.filter(age__div3__lte=3), [a3]) self.assertSequenceEqual(baseqs.filter(age__div3__in=[0, 2]), [a2, a3]) self.assertSequenceEqual(baseqs.filter(age__div3__in=[2, 4]), [a1, a2, a4]) self.assertSequenceEqual(baseqs.filter(age__div3__gte=3), [a1, a2, a3, a4]) self.assertSequenceEqual(baseqs.filter(age__div3__range=(1, 2)), [a1, a2, a4])
def test_custom_lookup_in_search_fields(self): band = Group.objects.create(name='The Hype') concert = Concert.objects.create(name='Woodstock', group=band) m = ConcertAdmin(Concert, custom_site) m.search_fields = ['group__name__cc'] with register_lookup(Field, Contains, lookup_name='cc'): request = self.factory.get('/', data={SEARCH_VAR: 'Hype'}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [concert]) request = self.factory.get('/', data={SEARCH_VAR: 'Woodstock'}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [])
def test_partial_gin_index_with_tablespace(self): with register_lookup(CharField, Length): index_name = 'char_field_gin_partial_idx' index = GinIndex( fields=['field'], name=index_name, condition=Q(field__length=40), db_tablespace='pg_default', ) with connection.schema_editor() as editor: editor.add_index(CharFieldModel, index) self.assertIn('TABLESPACE "pg_default" ', str(index.create_sql(CharFieldModel, editor))) constraints = self.get_constraints(CharFieldModel._meta.db_table) self.assertEqual(constraints[index_name]['type'], 'gin') with connection.schema_editor() as editor: editor.remove_index(CharFieldModel, index) self.assertNotIn(index_name, self.get_constraints(CharFieldModel._meta.db_table))
def test_spanning_relations_with_custom_lookup_in_search_fields(self): hype = Group.objects.create(name='The Hype') concert = Concert.objects.create(name='Woodstock', group=hype) vox = Musician.objects.create(name='Vox', age=20) Membership.objects.create(music=vox, group=hype) # Register a custom lookup on IntegerField to ensure that field # traversing logic in ModelAdmin.get_search_results() works. with register_lookup(IntegerField, Exact, lookup_name='exactly'): m = ConcertAdmin(Concert, custom_site) m.search_fields = ['group__members__age__exactly'] request = self.factory.get('/', data={SEARCH_VAR: '20'}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [concert]) request = self.factory.get('/', data={SEARCH_VAR: '21'}) request.user = self.superuser cl = m.get_changelist_instance(request) self.assertCountEqual(cl.queryset, [])
def test_call_order(self): with register_lookup(models.DateField, TrackCallsYearTransform): # junk lookup - tries lookup, then transform, then fails msg = "Unsupported lookup 'junk' for IntegerField or join on the field not permitted." with self.assertRaisesMessage(FieldError, msg): Author.objects.filter(birthdate__testyear__junk=2012) self.assertEqual(TrackCallsYearTransform.call_order, ['lookup', 'transform']) TrackCallsYearTransform.call_order = [] # junk transform - tries transform only, then fails with self.assertRaisesMessage(FieldError, msg): Author.objects.filter(birthdate__testyear__junk__more_junk=2012) self.assertEqual(TrackCallsYearTransform.call_order, ['transform']) TrackCallsYearTransform.call_order = [] # Just getting the year (implied __exact) - lookup only Author.objects.filter(birthdate__testyear=2012) self.assertEqual(TrackCallsYearTransform.call_order, ['lookup']) TrackCallsYearTransform.call_order = [] # Just getting the year (explicit __exact) - lookup only Author.objects.filter(birthdate__testyear__exact=2012) self.assertEqual(TrackCallsYearTransform.call_order, ['lookup'])
def test_transform(self): with register_lookup(DecimalField, ACos): DecimalModel.objects.create(n1=Decimal('0.5'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-0.9'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__acos__lt=2).get() self.assertEqual(obj.n1, Decimal('0.5'))
def test_transform(self): with register_lookup(DecimalField, Cos): DecimalModel.objects.create(n1=Decimal('-8.0'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('3.14'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__cos__gt=-0.2).get() self.assertEqual(obj.n1, Decimal('-8.0'))
def test_transform(self): with register_lookup(DecimalField, Sin): DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('0.1'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__sin__lt=0) self.assertQuerysetEqual(objs, [Decimal('5.4')], lambda a: a.n1)
def test_transform(self): with register_lookup(DecimalField, Round): DecimalModel.objects.create(n1=Decimal('2.0'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__round__gt=0).get() self.assertEqual(obj.n1, Decimal('2.0'))
def test_transform(self): with register_lookup(DecimalField, Exp): DecimalModel.objects.create(n1=Decimal('12.0'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__exp__gt=10) self.assertQuerysetEqual(objs, [Decimal('12.0')], lambda a: a.n1)
def test_transform(self): with register_lookup(DecimalField, Sign): DecimalModel.objects.create(n1=Decimal("5.4"), n2=Decimal("0")) DecimalModel.objects.create(n1=Decimal("-0.1"), n2=Decimal("0")) obj = DecimalModel.objects.filter(n1__sign__lt=0, n2__sign=0).get() self.assertEqual(obj.n1, Decimal("-0.1"))
def test_datetime_output_field(self): with register_lookup(models.PositiveIntegerField, DateTimeTransform): ut = MySQLUnixTimestamp.objects.create(timestamp=time.time()) y2k = timezone.make_aware(datetime(2000, 1, 1)) self.assertSequenceEqual(MySQLUnixTimestamp.objects.filter(timestamp__as_datetime__gt=y2k), [ut])
def test_transform(self): with register_lookup(DecimalField, ATan): DecimalModel.objects.create(n1=Decimal('3.12'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-5'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__atan__gt=0) self.assertQuerysetEqual(objs, [Decimal('3.12')], lambda a: a.n1)
def test_transform(self): with register_lookup(DecimalField, Radians): DecimalModel.objects.create(n1=Decimal('2.0'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__radians__gt=0).get() self.assertEqual(obj.n1, Decimal('2.0'))
def test_transform(self): with register_lookup(DecimalField, Round): DecimalModel.objects.create(n1=Decimal('2.0'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-1.0'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__round__gt=0) self.assertQuerysetEqual(objs, [Decimal('2.0')], lambda a: a.n1)
def test_transform(self): with register_lookup(DecimalField, Tan): DecimalModel.objects.create(n1=Decimal("0.0"), n2=Decimal("0")) DecimalModel.objects.create(n1=Decimal("12.0"), n2=Decimal("0")) obj = DecimalModel.objects.filter(n1__tan__lt=0).get() self.assertEqual(obj.n1, Decimal("12.0"))
def test_transform(self): with register_lookup(DecimalField, Sqrt): DecimalModel.objects.create(n1=Decimal("6.0"), n2=Decimal("0")) DecimalModel.objects.create(n1=Decimal("1.0"), n2=Decimal("0")) obj = DecimalModel.objects.filter(n1__sqrt__gt=2).get() self.assertEqual(obj.n1, Decimal("6.0"))
def test_transform(self): with register_lookup(CharField, SHA1): authors = Author.objects.filter( alias__sha1='e61a3587b3f7a142b8c7b9263c82f8119398ecb7', ).values_list('alias', flat=True) self.assertSequenceEqual(authors, ['John Smith'])
def test_transform(self): with register_lookup(DecimalField, Degrees): DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-30'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__degrees__gt=0).get() self.assertEqual(obj.n1, Decimal('5.4'))
def test_transform(self): with register_lookup(DecimalField, ATan): DecimalModel.objects.create(n1=Decimal('3.12'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-5'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__atan__gt=0).get() self.assertEqual(obj.n1, Decimal('3.12'))
def test_transform(self): with register_lookup(DecimalField, Sin): DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('0.1'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__sin__lt=0).get() self.assertEqual(obj.n1, Decimal('5.4'))
def test_transform(self): with register_lookup(DecimalField, Ceil): DecimalModel.objects.create(n1=Decimal("3.12"), n2=Decimal("0")) DecimalModel.objects.create(n1=Decimal("1.25"), n2=Decimal("0")) obj = DecimalModel.objects.filter(n1__ceil__gt=3).get() self.assertEqual(obj.n1, Decimal("3.12"))
def test_transform(self): with register_lookup(DecimalField, Floor): DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('3.4'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__floor__gt=4) self.assertQuerysetEqual(objs, [Decimal('5.4')], lambda a: a.n1)
def test_transform(self): with register_lookup(DecimalField, Sign): DecimalModel.objects.create(n1=Decimal('5.4'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-0.1'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__sign__lt=0, n2__sign=0).get() self.assertEqual(obj.n1, Decimal('-0.1'))
def test_transform(self): with register_lookup(DecimalField, ACos): DecimalModel.objects.create(n1=Decimal('0.5'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-0.9'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__acos__lt=2) self.assertQuerysetEqual(objs, [Decimal('0.5')], lambda a: a.n1)
def test_transform(self): with register_lookup(DecimalField, ASin): DecimalModel.objects.create(n1=Decimal('0.1'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('1.0'), n2=Decimal('0')) objs = DecimalModel.objects.filter(n1__asin__gt=1) self.assertQuerysetEqual(objs, [Decimal('1.0')], lambda a: a.n1)
def test_bilateral_inner_qs(self): with register_lookup(models.CharField, UpperBilateralTransform): msg = "Bilateral transformations on nested querysets are not implemented." with self.assertRaisesMessage(NotImplementedError, msg): Author.objects.filter( name__upper__in=Author.objects.values_list("name"))
def test_transform(self): with register_lookup(DecimalField, Abs): DecimalModel.objects.create(n1=Decimal('-1.5'), n2=Decimal('0')) DecimalModel.objects.create(n1=Decimal('-0.5'), n2=Decimal('0')) obj = DecimalModel.objects.filter(n1__abs__gt=1).get() self.assertEqual(obj.n1, Decimal('-1.5'))
def test_transform(self): with register_lookup(DecimalField, Floor): DecimalModel.objects.create(n1=Decimal("5.4"), n2=Decimal("0")) DecimalModel.objects.create(n1=Decimal("3.4"), n2=Decimal("0")) obj = DecimalModel.objects.filter(n1__floor__gt=4).get() self.assertEqual(obj.n1, Decimal("5.4"))