Skip to content

Commit efa19ae

Browse files
Fixed django#2559 -- Added cool new operators for Admin.search_fields, plus documentation. Thanks, Andy Dustman.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3601 bcc190cf-cafb-0310-a4f2-bffc1f526a37
1 parent eefe35c commit efa19ae

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ answer newbie questions, and generally made Django that much better:
6868
deric@monowerks.com
6969
dne@mayonnaise.net
7070
Jeremy Dunck <http://dunck.us/>
71+
Andy Dustman <farcepest@gmail.com>
7172
Clint Ecker
7273
gandalf@owca.info
7374
Baishampayan Ghose

django/contrib/admin/views/main.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,9 +711,19 @@ def get_query_set(self):
711711
qs = qs.order_by((self.order_type == 'desc' and '-' or '') + lookup_order_field)
712712

713713
# Apply keyword searches.
714+
def construct_search(field_name):
715+
if field_name.startswith('^'):
716+
return "%s__istartswith" % field_name[1:]
717+
elif field_name.startswith('='):
718+
return "%s__iexact" % field_name[1:]
719+
elif field_name.startswith('@'):
720+
return "%s__search" % field_name[1:]
721+
else:
722+
return "%s__icontains" % field_name
723+
714724
if self.lookup_opts.admin.search_fields and self.query:
715725
for bit in self.query.split():
716-
or_queries = [models.Q(**{'%s__icontains' % field_name: bit}) for field_name in self.lookup_opts.admin.search_fields]
726+
or_queries = [models.Q(**{construct_search(field_name): bit}) for field_name in self.lookup_opts.admin.search_fields]
717727
other_qs = QuerySet(self.model)
718728
other_qs = other_qs.filter(reduce(operator.or_, or_queries))
719729
qs = qs & other_qs

docs/model-api.txt

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -686,8 +686,8 @@ you can use the name of the model, rather than the model object itself::
686686
class Manufacturer(models.Model):
687687
# ...
688688

689-
Note, however, that you can only use strings to refer to models in the same
690-
models.py file -- you cannot use a string to reference a model in a different
689+
Note, however, that you can only use strings to refer to models in the same
690+
models.py file -- you cannot use a string to reference a model in a different
691691
application, or to reference a model that has been imported from elsewhere.
692692

693693
Behind the scenes, Django appends ``"_id"`` to the field name to create its
@@ -810,9 +810,9 @@ here's how you'd represent that::
810810

811811
As with ``ForeignKey``, a relationship to self can be defined by using the
812812
string ``'self'`` instead of the model name, and you can refer to as-yet
813-
undefined models by using a string containing the model name. However, you
814-
can only use strings to refer to models in the same models.py file -- you
815-
cannot use a string to reference a model in a different application, or to
813+
undefined models by using a string containing the model name. However, you
814+
can only use strings to refer to models in the same models.py file -- you
815+
cannot use a string to reference a model in a different application, or to
816816
reference a model that has been imported from elsewhere.
817817

818818
It's suggested, but not required, that the name of a ``ManyToManyField``
@@ -1386,6 +1386,41 @@ user searches for ``john lennon``, Django will do the equivalent of this SQL
13861386
WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
13871387
AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')
13881388

1389+
**New in Django development version:** For faster and/or more restrictive
1390+
searches, prefix the field name with an operator:
1391+
1392+
``^``
1393+
Matches the beginning of the field. For example, if ``search_fields`` is
1394+
set to ``['^first_name', '^last_name']`` and a user searches for
1395+
``john lennon``, Django will do the equivalent of this SQL ``WHERE``
1396+
clause::
1397+
1398+
WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%')
1399+
AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')
1400+
1401+
This query is more efficient than the normal ``'%john%'`` query, because
1402+
the database only needs to check the beginning of a column's data, rather
1403+
than seeking through the entire column's data. Plus, if the column has an
1404+
index on it, some databases may be able to use the index for this query,
1405+
even though it's a ``LIKE`` query.
1406+
1407+
``=``
1408+
Matches exactly, case-insensitive. For example, if
1409+
``search_fields`` is set to ``['=first_name', '=last_name']`` and
1410+
a user searches for ``john lennon``, Django will do the equivalent
1411+
of this SQL ``WHERE`` clause::
1412+
1413+
WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
1414+
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')
1415+
1416+
Note that the query input is split by spaces, so, following this example,
1417+
it's not currently not possible to search for all records in which
1418+
``first_name`` is exactly ``'john winston'`` (containing a space).
1419+
1420+
``@``
1421+
Performs a full-text match. This is like the default search method but uses
1422+
an index. Currently this is only available for MySQL.
1423+
13891424
Managers
13901425
========
13911426

0 commit comments

Comments
 (0)