Opened 8 years ago

Closed 6 years ago

#26184 closed New feature (fixed)

Allow using custom lookups and transforms in ModelAdmin.search_fields

Reported by: Bertrand Bordage Owned by: Krzysztof Nazarewski
Component: contrib.admin Version: dev
Severity: Normal Keywords:
Cc: berker.peksag@…, camilo.nova@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

When you define a ModelAdmin like this:

class MyAdmin(ModelAdmin):
    search_fields = ['my_field__unaccent']

a FieldDoesNotExist is raised when you try to search something.

This is because the admin fails to identify __unaccent as a valid lookup because django.contrib.admin.utils.lookup_needs_distinct relies on two kludges:

  • it assumes that the last part of the lookup expression is always a lookup (iexact, icontains, search, etc), and that all other parts are fields. In the unaccent scenario, the penultimate part is a transform since the admin generates this expression: myfield__unaccent__icontains
  • it only checks that lookups are in django.db.models.sql.constants.QUERY_TERMS. But QUERY_TERMS is no longer used and should be removed, it only contains "classic" lookups

The solution is to use the new registration API instead, with the get_lookup and get_transform methods.

A better solution would be to make search_fields more consistent with the rest of Django by removing the ^, =, & @ shortcuts. If not, providing them on the whole ORM would be consistent. In my opinion, they should be removed, they complicate Django while limiting its possibilities (what if someone wants exact instead of iexact?). If someone has a lot of fields with the same transforms/lookups, this can be done:

class BookAdmin(ModelAdmin):
    search_fields = ('title', 'subtitle', 'author_first_name', 'author_last_name', 'publisher')
    search_fields = [le + '__unaccent__icontains' for le in search_fields]

or even this if you need it often:

class SearchMixin:
    def get_search_fields(self, request):
        return [le + '__unaccent__icontains' for le in self.search_fields]

class BookAdmin(SearchMixin, ModelAdmin):
    search_fields = ('title', 'subtitle', 'author_first_name', 'author_last_name', 'publisher')

I’m working on an implementation for one of my projects, I’ll submit it when done.

Change History (10)

comment:1 by Bertrand Bordage, 8 years ago

Here’s a workaround that could work as a solution: dezede/dezede@5e8be29.
I kept get_search_results as is to leave the ^, =, & @ functionalities unchanged, but it should of course be changed, as suggested above.

comment:2 by Tim Graham, 8 years ago

Triage Stage: UnreviewedAccepted

comment:3 by Tim Graham, 8 years ago

Todo when implementing: check if it can solve #26001.

comment:4 by Berker Peksag, 8 years ago

Cc: berker.peksag@… added

comment:5 by Camilo Nova, 7 years ago

Cc: camilo.nova@… added

@Bertrand Bordage Did you work on that implementation?

in reply to:  5 comment:6 by Bertrand Bordage, 7 years ago

@Camilo Nova: No, I almost never use Django admin now, I switched to Wagtail.

comment:7 by Krzysztof Nazarewski, 7 years ago

Has patch: set
Owner: changed from nobody to Krzysztof Nazarewski
Status: newassigned

comment:8 by Tim Graham, 7 years ago

Patch needs improvement: set
Summary: Unable to use custom lookups or transforms in admin `search_fields`Allow using custom lookups and transforms in ModelAdmin.search_fields
Type: BugNew feature

comment:9 by Tim Graham, 6 years ago

Patch needs improvement: unset

New PR

comment:10 by Tim Graham <timograham@…>, 6 years ago

Resolution: fixed
Status: assignedclosed

In 244cc401:

Fixed #26184 -- Allowed using any lookups in ModelAdmin.search_fields.

Thanks Krzysztof Nazarewski for the initial patch.

Note: See TracTickets for help on using tickets.
Back to Top