Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django admin search with multiple words

I have troubles using the search_fields when the search expression has multiple words and i want to perform a startswith search

I have a class

class Foo(models.Model):
  kw = models.CharField(max_length = 255)
  ...

class FooAdmin(admin.ModelAdmin):
  search_fields = ('^kw',)

The '^' indicates that i want to perform a startswith search. If i'm looking for the kw 'foo fuu', django will perform the query:

select * from app_foo where `foo`.`kw` like 'foo%' and `foo`.`kw` like 'fuu%' 

This query obviously gives zero results. What should i do to make the engine looking for 'foo fuu%' ?

like image 357
Guillaume Thomas Avatar asked Jan 20 '13 16:01

Guillaume Thomas


3 Answers

How about override self.query so split() doesn't work?

from django.contrib.admin.views.main import ChangeList


class UnsplitableUnicode(str):
    "An object that behaves like a unicode string but cannot be split()"
    def split(self, *args, **kwargs):
        return [self]

class MultiWordSearchChangeList(ChangeList):
    "Changelist that allows searches to contain spaces"
    def get_query_set(self, request):
        self.query = UnsplitableUnicode(self.query)
        return super(MultiWordSearchChangeList, self).get_query_set(request)

class FooAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return MultiWordSearchChangeList
like image 149
Mike Fogel Avatar answered Sep 17 '22 14:09

Mike Fogel


As mentioned by Thai Tran it's a bit messy. Here is the section you would have to edit.

from django.contrib import admin
from django.contrib.admin.views.main import ChangeList

class CustomChangeList(ChangeList):
    def get_query_set(self, request):
        #Basically copy and paste in entire function and edit the piece copied in here.

        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(**{orm_lookup: bit})
                              for orm_lookup in orm_lookups]
                qs = qs.filter(reduce(operator.or_, or_queries))
            if not use_distinct:
                for search_spec in orm_lookups:
                    if lookup_needs_distinct(self.lookup_opts, search_spec):
                        use_distinct = True
                        break


class FooAdmin(admin.ModelAdmin):
    def get_changelist(self, request, **kwargs):
        return CustomChangeList

Speaking from experience, overriding ChangeList has caused problems down the road.

like image 41
Nathaniel Avatar answered Sep 20 '22 14:09

Nathaniel


Here is a snippet link that can make advanced search for admin:

http://djangosnippets.org/snippets/2322/

like image 34
catherine Avatar answered Sep 19 '22 14:09

catherine