13

In the django admin search bar if i had a model with a column = fruit_name and I wanted to search that column for all instances with either the fruit_name = banana or apple which would show all of the bananas and apples, how could I do that?

user3806832
  • 663
  • 9
  • 22

3 Answers3

19

Override the ModelAdmin.get_search_results` method:

from operator import or_
from django.db.models import Q

class MyAdmin(admin.ModelAdmin):
    ...
    def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super(MyAdmin, self).get_search_results(
                                               request, queryset, search_term)
        search_words = search_term.split()
        if search_words:
            q_objects = [Q(**{field + '__icontains': word})
                                for field in self.search_fields
                                for word in search_words]
            queryset |= self.model.objects.filter(reduce(or_, q_objects))
    return queryset, use_distinct
catavaran
  • 44,703
  • 8
  • 98
  • 85
  • A useful option here is to define a delimiter (i.e., `, ` [comma-space]) and add this to `split`. `search_words = search_term.split(", ")`. This allows you to manually delimit the search terms. – YPCrumble Feb 01 '18 at 16:32
  • Where did you get `reduce` from? – Valachio Dec 04 '18 at 01:06
  • 1
    In python 2.7 `reduce` is a built-in function. In python 3 you have to import it from `functools`. – catavaran Dec 05 '18 at 02:42
2

In your admin.py file you can customize the presentation of the models.

class YourModelAdmin(admin.ModelAdmin):
       list_display = ('id_proveedor','anio','mes','fecha','fecha_mod','contacto','usuario','obs')
       list_display_links = ('id_proveedor','anio','mes','fecha','fecha_mod','contacto','usuario','obs')
       list_filter = ('id_proveedor','anio','mes')
       ordering = ['id_proveedor']
       search_fields = ('id_proveedor','anio','mes','contacot')
       list_per_page = 10

admin.site.register(YourModel, YourModelAdmin)

You can customize for what fields you want the search, the fields you wanna display, the ordering etc.

check the documentation about the admin page

Joseleg
  • 393
  • 9
  • 35
1

In my case, using @catavaran's answer would break filters as asked here. I came up with the following work-around:

from operator import or_
from django.db.models import Q

class MyAdmin(admin.ModelAdmin):
    ...
    def get_search_results(self, request, queryset, search_term):
        orig_queryset = queryset
        queryset, use_distinct = super(MyAdmin, self).get_search_results(
                                               request, queryset, search_term)
        search_words = search_term.split()
        if search_words:
            q_objects = [Q(**{field + '__icontains': word})
                                for field in self.search_fields
                                for word in search_words]
            queryset |= self.model.objects.filter(reduce(or_, q_objects))

    queryset = queryset & orig_queryset

    return queryset, use_distinct

This makes sure that ant previous filtering is not overridden when we use queryset |= self.model.objects.filter(reduce(or_, q_objects)). The use of orig_queryset, on the other hand, ensures that any chosen filters also get applied.

Stunts
  • 430
  • 6
  • 11