Opened 6 years ago

Closed 5 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 Changed 6 years ago by Bertrand Bordage

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 Changed 6 years ago by Tim Graham

Triage Stage: UnreviewedAccepted

comment:3 Changed 6 years ago by Tim Graham

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

comment:4 Changed 6 years ago by Berker Peksag

Cc: berker.peksag@… added

comment:5 Changed 5 years ago by Camilo Nova

Cc: camilo.nova@… added

@Bertrand Bordage Did you work on that implementation?

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

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

comment:7 Changed 5 years ago by Krzysztof Nazarewski

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

comment:8 Changed 5 years ago by Tim Graham

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 Changed 5 years ago by Tim Graham

Patch needs improvement: unset

New PR

comment:10 Changed 5 years ago by Tim Graham <timograham@…>

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