2013-09-22 35 views
1

這是一個django-filter特定於應用程序的問題。改變Django過濾默認行爲

有沒有人試圖引入過濾條件來根據條件進行查詢?

讓我舉一個例子:

假設我們有一個Product模型。它可以根據其nameprice進行過濾。

默認django-filter的行爲是,因爲我們使用更多的過濾器並將它們鏈接在一起,所以它們使用AND語句(它縮小了搜索範圍)過濾數據。

我想改變這種行爲並添加一個ChoiceFilter,比如說有兩個選項:AND以及OR。從這一點來看,過濾器應該根據用戶選擇的內容來工作。

例如,如果用戶查詢含有name__startswith="Juice"ORprice__lte=10.00的產品,則應列出名稱以Juice開頭的所有產品以及價格低於10.00的產品。

Django-filter文件說,該過濾器可以帶參數:

action 

An optional callable that tells the filter how to handle the queryset. It recieves a 
QuerySet and the value to filter on and should return a Queryset that is filtered 
appropriately. 

這似乎是我所期待的,但該文檔沒有任何進一步的解釋。請提出建議?

@EDIT:

這是views.py

def product_list(request): 
    f = ProductFilter(request.GET, queryset=Product.objects.all()) 
    return render_to_response('my_app/template.html', {'filter': f}) 

回答

2

action將不會削減它。此回調用於特定的篩選字段,並且只能訪問該字段的值。

最簡潔的方法是創建多窗口小部件過濾器字段,類似於RangeField。檢查出source

所以不是兩個日期字段使用nameprice和邏輯型[AND|OR]的領域,這樣你在一次訪問所有這些值在自定義查詢集使用。

編輯1:

這是一個小要點我寫來展示如何查詢與選擇的運營商兩個字段。 https://gist.github.com/mariodev/6689472

用法:

class ProductFilter(django_filters.FilterSet): 
    nameprice = NamePriceFilter() 

    class Meta: 
     model = Product 
     fields = ['nameprice'] 

它實際上不是在重新使用方面非常靈活,但肯定可以重新分解,使有益。

+0

感謝您對此問題的關注。你能給出一個快速代碼的例子嗎?我想我不知道如何將這個'[AND | OR]'邏輯類型用作字段。 – nutship

+0

@shipship我會用自己的代碼更新我的帖子(因爲我也對這個問題感興趣)。 '[AND | OR]'表示爲無線電或選擇字段,只要將其視爲典型的過濾字段並使用它的值構造AND或OR查詢集。 – mariodev

+0

謝謝。啊,所以基本上我們構造一個查詢集是'views.py',然後傳遞給''queryset'變量(而不是默認的'Product.objects.all()')? – nutship

2

由於構建最終查詢集的方式,使每個過濾器進行OR操作都很困難。從本質上講,代碼是這樣的:

FilterSet,filterset.py line 253

 
@property 
def qs(self): 
    qs = self.queryset.all() 
    for filter_ in self.filters(): 
     qs = filter_.filter(qs) 

過濾器,filters.py line 253

 
def filter(self, qs): 
    return qs.filter(name=self.value) 

每個過濾器可以決定如何讓自己在進入查詢集,和所有過濾器按照當前實施,使用AND過濾傳入的查詢集。您可以創建一組新的過濾器或自己的傳入查詢集,但是無法覆蓋FilterSet方面的行爲。

1

爲了使過濾器工作或,你應該讓蒂姆的回答類似這樣的FilterSet和覆蓋QS的一個子類:

@property 
def qs(self): 
    qs = self.queryset.none() 
    for filter_ in self.filters(): 
     qs |= filter_.filter(self.queryset.all()) 

我沒有測試過這一點,但我覺得你有這個想法。 QuerySets支持按位操作,因此您可以輕鬆地將兩個過濾器的結果與OR組合。

+0

謝謝你們花時間回覆。我將不得不花上一兩天的時間,希望能讓它工作。 – nutship

1
 



class FileFilterSet(django_filters.FilterSet): 
    class Meta: 
     model = File 
     fields = ['project'] 

    def __init__(self, *args, **kwargs): 
     super(FileFilterSet, self).__init__(*args, **kwargs) 

     for name, field in self.filters.items(): 
      if isinstance(field, ModelChoiceFilter): 
       field.extra['empty_label'] = None 
       field.extra['initial'] = Project.objects.get(pk=2) 
       # field.extra['queryset'] = Project.objects.filter(pk=2) 


class FileFilter(FilterView): 
    model = File 
    template_name = 'files_list.html' 
    filterset_class = FileFilterSet 
 
+0

向你的代碼添加一些解釋。 –