diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index 7714668b9b6..86ec9c22225 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -358,6 +358,13 @@ default_lookups['isnull'] = IsNull class Search(BuiltinLookup): lookup_name = 'search' + + def as_sql(self, qn, connection): + lhs, lhs_params = self.process_lhs(qn, connection) + rhs, rhs_params = self.process_rhs(qn, connection) + sql_template = connection.ops.fulltext_search_sql(field_name=lhs) + return sql_template, lhs_params + rhs_params + default_lookups['search'] = Search diff --git a/tests/lookup/models.py b/tests/lookup/models.py index df8b26c4e97..0b4c88b8ed3 100644 --- a/tests/lookup/models.py +++ b/tests/lookup/models.py @@ -65,3 +65,15 @@ class Player(models.Model): def __str__(self): return self.name + + +# To test __search lookup a fulltext index is needed. This +# is only available when using MySQL 5.6, or when using MyISAM +# tables. As 5.6 isn't common yet, lets use MyISAM table for +# testing. The table is manually created by the test method. +class MyISAMArticle(models.Model): + headline = models.CharField(max_length=100) + + class Meta: + db_table = 'myisam_article' + managed = False diff --git a/tests/lookup/tests.py b/tests/lookup/tests.py index 04d9f0fc9ea..67443146256 100644 --- a/tests/lookup/tests.py +++ b/tests/lookup/tests.py @@ -2,11 +2,13 @@ from __future__ import unicode_literals from datetime import datetime from operator import attrgetter +from unittest import skipUnless from django.core.exceptions import FieldError -from django.test import TestCase, skipUnlessDBFeature +from django.db import connection +from django.test import TestCase, TransactionTestCase, skipUnlessDBFeature -from .models import Author, Article, Tag, Game, Season, Player +from .models import Author, Article, Tag, Game, Season, Player, MyISAMArticle class LookupTests(TestCase): @@ -710,3 +712,27 @@ class LookupTests(TestCase): self.assertEqual(Player.objects.filter(games__season__gt=333).distinct().count(), 2) self.assertEqual(Player.objects.filter(games__season__year__gt=2010).distinct().count(), 2) self.assertEqual(Player.objects.filter(games__season__gt__gt=222).distinct().count(), 2) + + +class LookupTransactionTests(TransactionTestCase): + available_apps = ['lookup'] + + @skipUnless(connection.vendor == 'mysql', 'requires MySQL') + def test_mysql_lookup_search(self): + # To use fulltext indexes on MySQL either version 5.6 is needed, or one must use + # MyISAM tables. Neither of these combinations is currently available on CI, so + # lets manually create a MyISAM table for Article model. + with connection.cursor() as cursor: + cursor.execute( + "CREATE TEMPORARY TABLE myisam_article (" + " id INTEGER PRIMARY KEY AUTO_INCREMENT, " + " headline VARCHAR(100) NOT NULL " + ") ENGINE MYISAM") + dr = MyISAMArticle.objects.create(headline='Django Reinhardt') + MyISAMArticle.objects.create(headline='Ringo Star') + # NOTE: Needs to be created after the article has been saved. + cursor.execute( + 'CREATE FULLTEXT INDEX myisam_article_ft ON myisam_article (headline)') + self.assertQuerysetEqual( + MyISAMArticle.objects.filter(headline__search='Reinhardt'), + [dr], lambda x: x)