2013-01-20 106 views
6

我有使用search_fields當搜索表達式具有多個字的麻煩,我想執行startswith搜索Django管理搜索

我有一個類

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

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

'^'指示我想執行一次startswith搜索。如果我正在查找kw'foo fuu',django將執行查詢:

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

此查詢明顯給出零結果。我該怎麼做才能讓引擎尋找'foo fuu%'

+0

似乎Django的分割上的空間查詢,以便這可能是不可能的事。你用'@'考慮了全文選項嗎? –

+0

這是可以改變拆分標記嗎? –

+0

不是我所知道的。該文檔說:'請注意,查詢輸入被空格分割,所以,在此示例之後,目前無法搜索其中first_name正好是'john winston'(包含空格)的所有記錄。' –

回答

12

覆蓋如何self.query因此split()不起作用?

class UnsplitableUnicode(unicode): 
    "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 
+0

這個解決方案看起來很優雅,但我無法使它工作。你試過了嗎?我不能進入經常分裂的方法,我不明白爲什麼 –

+0

謝謝,更新。因爲'ChangeList .__ init__'都設置'self.query' *和*使用它,所以我應該因爲在SO上發佈代碼而沒有先測試它而被打耳光......它在'__init__'中不起作用。在'get_query_set()'中覆蓋它可以讓我們在使用之前捕獲'self.query'。 –

2

正如Thai Tran所提到的那樣有點混亂。這是您必須編輯的部分。

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 

從經驗來看,覆蓋ChangeList已經引起了問題。

+0

到目前爲止,這是最差的解決方案,但是在發佈新的Django版本後,我擔心兼容性問題。但是,謝謝 –

+0

是的。我們去年因爲某種原因而忽略了一個ChangeList,當1.4出來時我們不得不把它翻出來......經驗教訓。如果我們被迫再次這樣做,我會清楚地記錄它。 – Nathaniel