diff --git a/django/contrib/admin/views/main.py b/django/contrib/admin/views/main.py index 635330f6a8..4b56348318 100644 --- a/django/contrib/admin/views/main.py +++ b/django/contrib/admin/views/main.py @@ -254,12 +254,15 @@ class ChangeList(object): return "%s__icontains" % field_name if self.search_fields and self.query: + orm_lookups = [construct_search(str(search_field)) + for search_field in self.search_fields] for bit in self.query.split(): - or_queries = [models.Q(**{construct_search(str(field_name)): bit}) for field_name in self.search_fields] + or_queries = [models.Q(**{orm_lookup: bit}) + for orm_lookup in orm_lookups] qs = qs.filter(reduce(operator.or_, or_queries)) if not use_distinct: - for search_field in self.search_fields: - field_name = search_field.split('__', 1)[0] + for search_spec in orm_lookups: + field_name = search_spec.split('__', 1)[0] f = self.lookup_opts.get_field_by_name(field_name)[0] if hasattr(f, 'rel') and isinstance(f.rel, models.ManyToManyRel): use_distinct = True diff --git a/tests/regressiontests/admin_views/models.py b/tests/regressiontests/admin_views/models.py index 9ac99cc9ef..3b44f94d8b 100644 --- a/tests/regressiontests/admin_views/models.py +++ b/tests/regressiontests/admin_views/models.py @@ -258,7 +258,7 @@ class PersonAdmin(admin.ModelAdmin): list_display = ('name', 'gender', 'alive') list_editable = ('gender', 'alive') list_filter = ('gender',) - search_fields = (u'name',) + search_fields = ('^name',) ordering = ["id"] save_as = True @@ -445,7 +445,7 @@ class Recommendation(Title): recommender = models.ForeignKey(Recommender) class RecommendationAdmin(admin.ModelAdmin): - search_fields = ('titletranslation__text', 'recommender__titletranslation__text',) + search_fields = ('=titletranslation__text', '=recommender__titletranslation__text',) class Collector(models.Model): name = models.CharField(max_length=100) diff --git a/tests/regressiontests/admin_views/tests.py b/tests/regressiontests/admin_views/tests.py index 6be07b462d..ff97acd878 100644 --- a/tests/regressiontests/admin_views/tests.py +++ b/tests/regressiontests/admin_views/tests.py @@ -1288,11 +1288,11 @@ class SecureViewTests(TestCase): user_ctype = ContentType.objects.get_for_model(User) user = User.objects.get(username='super') shortcut_url = "/test_admin/admin/r/%s/%s/" % (user_ctype.pk, user.pk) - + # Not logged in: we should see the login page. response = self.client.get(shortcut_url, follow=False) self.assertTemplateUsed(response, 'admin/login.html') - + # Logged in? Redirect. self.client.login(username='super', password='secret') response = self.client.get(shortcut_url, follow=False) @@ -1470,7 +1470,7 @@ class AdminViewListEditable(TestCase): "_save": "Save", } - self.client.post('/test_admin/admin/admin_views/person/?q=mauchly', data) + self.client.post('/test_admin/admin/admin_views/person/?q=john', data) self.assertEqual(Person.objects.get(name="John Mauchly").alive, False) @@ -1680,7 +1680,8 @@ class AdminViewListEditable(TestCase): class AdminSearchTest(TestCase): - fixtures = ['admin-views-users','multiple-child-classes'] + fixtures = ['admin-views-users', 'multiple-child-classes', + 'admin-views-person'] def setUp(self): self.client.login(username='super', password='secret') @@ -1703,6 +1704,26 @@ class AdminSearchTest(TestCase): self.assertContains(response, "\n1 user\n") self.assertContains(response, '') + def test_exact_matches(self): + response = self.client.get('/test_admin/admin/admin_views/recommendation/?q=bar') + # confirm the search returned one object + self.assertContains(response, "\n1 recommendation\n") + + response = self.client.get('/test_admin/admin/admin_views/recommendation/?q=ba') + # confirm the search returned zero objects + self.assertContains(response, "\n0 recommendations\n") + + def test_beginning_matches(self): + response = self.client.get('/test_admin/admin/admin_views/person/?q=Gui') + # confirm the search returned one object + self.assertContains(response, "\n1 person\n") + self.assertContains(response, "Guido") + + response = self.client.get('/test_admin/admin/admin_views/person/?q=uido') + # confirm the search returned zero objects + self.assertContains(response, "\n0 persons\n") + self.assertNotContains(response, "Guido") + class AdminInheritedInlinesTest(TestCase): fixtures = ['admin-views-users.xml',]