2009-09-21 41 views
6

Tôi đang sử dụng bộ lọc django rất thú vị (thông qua: http://github.com/alex/django-filter) và dường như không thể quấn quanh đầu tài liệu hoặc có thể chỉ cần cần tăng một chút.Sử dụng 'bộ lọc django' với trường LỰA CHỌN - cần tùy chọn "Bất kỳ"

Khi tôi hiển thị biểu mẫu bộ lọc trên trang danh sách đối tượng, cho trường FK I lấy danh sách thả xuống bao gồm "-----" kết quả trong bộ lọc loại "bất kỳ" . Nhưng tôi có một số lựa chọn được đặt thành một trường trên mô hình đó và tôi muốn có cùng một tùy chọn loại "bất kỳ". Dưới đây là một phần ví dụ có liên quan từ models.py:

TICKET_STATUS_CHOICES = (
    ('new', 'New'), 
    ('accepted', 'Accepted'), 
    ('assigned', 'Assigned'), 
    ('reopened', 'Reopened'), 
    ('closed', 'Closed'), 
) 

class Ticket(models.Model): 
    assigned_to = models.ForeignKey(User, null=True, blank=True) 
    status = models.CharField(max_length=20, 
choices=TICKET_STATUS_CHOICES, default='new') 

import django_filters 

class TicketFilter(django_filters.FilterSet): 
    class Meta: 
     model = Ticket 
     fields = ['assigned_to', 'status'] 

Khi tôi hiển thị dưới dạng lọc, 'assigned_to' được một 'bất kỳ' tùy chọn, như cũng như danh sách người sử dụng có sẵn. Trường 'status', tuy nhiên, là chỉ giới hạn ở các tùy chọn được liệt kê trong '_CHOICES' thực tế.

Làm cách nào để thêm tùy chọn 'bất kỳ' vào các trường dựa trên _CHOICES?

Trả lời

6

Như đã đề cập trong các tài liệu 'sử dụng' ngắn nhưng ngọt ngào,

lọc cũng cần đối số từ khóa tùy ý mà có được thông qua vào constructor django.forms.Field.

Điều này không có ý nghĩa nhiều cho đến khi tôi nhìn xa hơn một chút. Trong thư mục ./django-filter/docs/ref/, có filters.txt mô tả Trường Bộ lọc và trường Mô hình nào chúng tương tác theo mặc định. (Tôi nghĩ rằng tôi đã có ngôn ngữ ở đây, nếu không, hãy sửa tôi).

Vì vậy, chúng ta có thể thấy rằng ChoiceFilter được sử dụng cho bất kỳ trường nào "có lựa chọn".

Nhấn lên tài liệu Django, điều quan trọng ở đây là Trường mẫu và cách chúng tương tác với Mô hình. (Sử dụng các hình thức Django). Vì vậy, chúng ta thấy ChoiceField (http://docs.djangoproject.com/en/dev/ref/forms/fields/#choicefield) mà nói

Đưa thêm một đối số cần thiết: ChoiceField.choices Một iterable (ví dụ, một danh sách hoặc tuple) 2-tuples để sử dụng như lựa chọn cho lĩnh vực này.

Vì vậy, bạn có thể chuyển danh sách đó, không chỉ các lựa chọn Tuple ban đầu được đặt.

Vì vậy, đây có thể không phải pythonic hoặc khô, nhưng đây là cách tôi đã thay đổi mô hình trong câu hỏi:

class TicketFilter(django_filters.FilterSet): 
    class Meta: 
     model = Ticket 
     fields = ['assigned_to', 'priority', 'status'] 

    def __init__(self, *args, **kwargs): 
     super(TicketFilter, self).__init__(*args, **kwargs) 
     self.filters['priority'].extra.update(
      { 
       'choices': CHOICES_FOR_PRIORITY_FILTER 
      }) 

Và trên đó, nơi _CHOICES của tôi đã được xác định, tôi định nghĩa mới này (nêu trên) và làm chắc chắn thêm sự lựa chọn ban đầu đến cuối:

CHOICES_FOR_PRIORITY_FILTER = [ 
    ('', 'Any'), 
] 
CHOICES_FOR_PRIORITY_FILTER.extend(list(TICKET_PRIORITY_CHOICES)) 

tôi đang sử dụng danh sách() ở đây vì lựa chọn ban đầu đã được thiết lập trong một tuple, vì vậy tôi muốn biến chúng thành một danh sách. Ngoài ra, nếu bạn gặp lỗi NoneType, hãy đảm bảo bạn không cố gán 'giá trị trả lại' là .extend(), bởi vì không có. Tôi vấp phải điều này, bởi vì tôi quên rằng đó là một phương thức của một list, và không phải là một hàm trả về một danh sách mới.

Nếu bạn biết cách dễ dàng hơn, DRY hoặc "pythonic" hơn để thực hiện việc này, vui lòng cho tôi biết!

6

DRY'er sẽ sử dụng đối số 'lựa chọn' đã được xác định cho ChoiceFilter.

Vì vậy, bạn chỉ có thể mở rộng FILTER_CHOICES của bạn sẽ được TICKET_STATUS_CHOICES của bạn cộng với một 'bất kỳ' tùy chọn với chuỗi rỗng:

FILTER_CHOICES = (
    ('new', 'New'), 
    ('accepted', 'Accepted'), 
    ('assigned', 'Assigned'), 
    ('reopened', 'Reopened'), 
    ('closed', 'Closed'), 
    ('', 'Any'), 
) 

Và TicketFilter bạn sẽ là:

class TicketFilter(django_filters.FilterSet): 

    status = django_filters.ChoiceFilter(choices=FILTER_CHOICES) 

    class Meta: 
     model = Ticket 
     fields = ['assigned_to'] 
2

Dựa trên tác phẩm của kẻ hèn nhát vô danh, tôi đã làm như sau:

import django_filters 

from .models import Experiment 

EMPTY_CHOICE = ('', '---------'), # Don't forget the trailing comma 

class ExperimentFilter(django_filters.FilterSet): 
    class Meta: 
     model = Experiment 
     fields = ['method__year',] 

    def __init__(self, *args, **kwargs): 
     super(ExperimentFilter, self).__init__(*args, **kwargs) 
     self.filters['method__year'].extra['choices'] = EMPTY_CHOICE + \ 
      self.filters['method__year'].extra['choices'] 
1

Tôi kết hợp tất cả các phương pháp trên si nce Tôi không thích chỉ định tất cả các trường cần được cập nhật và kết thúc bằng một cái gì đó như thế này:

import django_filters 

from django.db import models 
from django_filters.filters import ChoiceFilter 

EMPTY_CHOICE = ('', '---------') 

class TicketFilter(django_filters.FilterSet): 
    def __init__(self, *args, **kwargs): 
     super(TicketFilter, self).__init__(*args, **kwargs) 
     # add empty choice to all choice fields: 
     choices = filter(
      lambda f: isinstance(self.filters[f], ChoiceFilter), 
      self.filters) 

     for field_name in choices: 
      extended_choices = ((EMPTY_CHOICE,) + 
           self.filters[field_name].extra['choices']) 
      self.filters[field_name].extra['choices'] = extended_choices 

Công việc nào.

0

Thậm chí ngắn hơn là sử dụng nhãn rỗng:

class TicketFilter(FilterSet): 

    status = ChoiceFilter(choices=Ticket.CHOICES, empty_label=ugettext_lazy(u'Any')) 

    class Meta: 
     model = Ticket 
     fields = ('status',) 
Các vấn đề liên quan