Bộ lọc mặc định trong quản trị Django


94

Làm cách nào để thay đổi lựa chọn bộ lọc mặc định từ 'TẤT CẢ'? Tôi có một trường có tên như statustrong đó có ba giá trị: activate, pendingrejected. Khi tôi sử dụng list_filtertrong quản trị Django, theo mặc định, bộ lọc được đặt thành 'Tất cả' nhưng tôi muốn đặt bộ lọc thành đang chờ xử lý theo mặc định.

Câu trả lời:


102

Để đạt được điều này có liên kết 'Tất cả' có thể sử dụng trong thanh bên của bạn (tức là liên kết hiển thị tất cả thay vì hiển thị đang chờ xử lý), bạn cần tạo bộ lọc danh sách tùy chỉnh, kế thừa từ django.contrib.admin.filters.SimpleListFiltervà lọc trên 'đang chờ xử lý' theo mặc định. Một cái gì đó dọc theo những dòng này sẽ hoạt động:

from datetime import date

from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter

class StatusFilter(SimpleListFilter):
    title = _('Status')

    parameter_name = 'status'

    def lookups(self, request, model_admin):
        return (
            (None, _('Pending')),
            ('activate', _('Activate')),
            ('rejected', _('Rejected')),
            ('all', _('All')),
        )

    def choices(self, cl):
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == lookup,
                'query_string': cl.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

    def queryset(self, request, queryset):
        if self.value() in ('activate', 'rejected'):
            return queryset.filter(status=self.value())    
        elif self.value() == None:
            return queryset.filter(status='pending')


class Admin(admin.ModelAdmin): 
    list_filter = [StatusFilter] 

CHỈNH SỬA: Yêu cầu Django 1.4 (cảm ơn Simon)


3
Đây là giải pháp sạch sẽ nhất, nhưng nó có ít lượt ủng hộ nhất ... tuy nhiên, nó yêu cầu Django 1.4, mặc dù bây giờ nên được đưa ra.
Simon

@Greg Làm cách nào để bạn xóa hoàn toàn chức năng của bộ lọc và tab bộ lọc ra khỏi trang quản trị?


2
Giải pháp này có một nhược điểm nhỏ. Khi bộ lọc trống (bộ lọc 'đang chờ xử lý' thực sự được sử dụng), Django 1.8 xác định không chính xác tổng số kết quả đầy đủ và không hiển thị số kết quả nếu show_full_result_count là True (theo mặc định). -
Alexander Fedotov

Lưu ý rằng nếu bạn không ghi đè choicesphương thức trong giải pháp, nó sẽ tiếp tục thêm tùy chọn Tất cả của chính nó ở đầu danh sách các lựa chọn.
richard

47
class MyModelAdmin(admin.ModelAdmin):   

    def changelist_view(self, request, extra_context=None):

        if not request.GET.has_key('decommissioned__exact'):

            q = request.GET.copy()
            q['decommissioned__exact'] = 'N'
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

18
Giải pháp này có nhược điểm là mặc dù lựa chọn "Tất cả" vẫn hiển thị trong giao diện người dùng, việc chọn nó vẫn áp dụng chế độ lọc mặc định.
akaihola

i có cùng một câu hỏi, nhưng tôi có thể hiểu được phát lại ... xin lỗi im mới với Django ... nhưng có lẽ điều này sẽ làm việc blog.dougalmatthews.com/2008/10/...
Asinox

Điều này là tốt nhưng tôi cần xem thông số get trong url để bộ lọc của tôi có thể nhận và hiển thị nó được chọn. Đăng giải pháp của tôi trong thời gian ngắn.
radtek

giải thích thiếu. chỉ đăng một đoạn mã có thể không giúp ích cho tất cả mọi người. trên hết, nó không hoạt động và không có một chút ngữ cảnh, thật khó để tìm ra lý do tại sao
EvilSmurf

19

Lấy câu trả lời của ha22109 ở trên và sửa đổi để cho phép chọn "Tất cả" bằng cách so sánh HTTP_REFERERPATH_INFO.

class MyModelAdmin(admin.ModelAdmin):

    def changelist_view(self, request, extra_context=None):

        test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])

        if test[-1] and not test[-1].startswith('?'):
            if not request.GET.has_key('decommissioned__exact'):

                q = request.GET.copy()
                q['decommissioned__exact'] = 'N'
                request.GET = q
                request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

3
Điều này đã xảy ra với tôi vì HTTP_REFERER không phải lúc nào cũng hiện diện. Tôi đã thực hiện 'referencer = request.META.get (' HTTP_REFERER ',' '); test = referencer.split (request.META ['PATH_INFO']) '
ben author

@Ben Tôi đang sử dụng hai dòng của bạn là referencer = request.META.get ('HTTP_REFERER', '') test = referencer.split (request.META ['PATH_INFO']). Tôi không biết nhiều về HTTP_REFERER. Sự cố có được khắc phục hoàn toàn từ những dòng này không nếu HTTP_REFERER không có.
the_game

@the_game vâng, ý tưởng là nếu bạn sử dụng dấu ngoặc vuông để cố gắng truy cập vào một khóa không tồn tại, nó sẽ ném KeyError, nếu bạn sử dụng get()phương thức của dict, bạn có thể chỉ định một khóa mặc định. Tôi đã chỉ định một mặc định của chuỗi rỗng để split () không ném AttributeError. Đó là tất cả.
ben author

@Ben. Cảm ơn nó hiệu quả với tôi. Ngoài ra, bạn có thể trả lời câu hỏi này không, tôi tin rằng đây là phần mở rộng cho câu hỏi này chỉ stackoverflow.com/questions/10410982/… . Bạn có thể vui lòng cung cấp cho tôi một giải pháp cho điều này.
the_game

1
Điều này hoạt động tốt. mặc dù has_key()không được ủng hộ key in d. Nhưng tôi biết bạn chỉ lấy từ câu trả lời của ha22109. Một câu hỏi: tại sao sử dụng request.META['PATH_INFO']khi bạn chỉ có thể sử dụng request.path_info(ngắn hơn)?
Nick

19

Tôi biết câu hỏi này đã khá cũ, nhưng nó vẫn có giá trị. Tôi tin rằng đây là cách làm đúng nhất. Về cơ bản nó giống với phương pháp của Greg, nhưng được xây dựng dưới dạng một lớp có thể mở rộng để dễ dàng sử dụng lại.

from django.contrib.admin import SimpleListFilter
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _

class DefaultListFilter(SimpleListFilter):
    all_value = '_all'

    def default_value(self):
        raise NotImplementedError()

    def queryset(self, request, queryset):
        if self.parameter_name in request.GET and request.GET[self.parameter_name] == self.all_value:
            return queryset

        if self.parameter_name in request.GET:
            return queryset.filter(**{self.parameter_name:request.GET[self.parameter_name]})

        return queryset.filter(**{self.parameter_name:self.default_value()})

    def choices(self, cl):
        yield {
            'selected': self.value() == self.all_value,
            'query_string': cl.get_query_string({self.parameter_name: self.all_value}, []),
            'display': _('All'),
        }
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == force_text(lookup) or (self.value() == None and force_text(self.default_value()) == force_text(lookup)),
                'query_string': cl.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

class StatusFilter(DefaultListFilter):
    title = _('Status ')
    parameter_name = 'status__exact'

    def lookups(self, request, model_admin):
        return ((0,'activate'), (1,'pending'), (2,'rejected'))

    def default_value(self):
        return 1

class MyModelAdmin(admin.ModelAdmin):
    list_filter = (StatusFilter,)

8

Đây là giải pháp chung của tôi sử dụng chuyển hướng, nó chỉ kiểm tra xem có bất kỳ tham số GET nào không, nếu không có thì nó chuyển hướng với tham số get mặc định. Tôi cũng có một bộ list_filter để nó chọn và hiển thị mặc định.

from django.shortcuts import redirect

class MyModelAdmin(admin.ModelAdmin):   

    ...

    list_filter = ('status', )

    def changelist_view(self, request, extra_context=None):
        referrer = request.META.get('HTTP_REFERER', '')
        get_param = "status__exact=5"
        if len(request.GET) == 0 and '?' not in referrer:
            return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

Cảnh báo duy nhất là khi bạn truy cập trực tiếp vào trang bằng "?" hiện trong url, không có bộ HTTP_REFERER nên nó sẽ sử dụng tham số mặc định và chuyển hướng. Điều này ổn đối với tôi, nó hoạt động tuyệt vời khi bạn nhấp qua bộ lọc quản trị viên.

CẬP NHẬT :

Để giải quyết vấn đề báo trước, tôi đã viết một hàm bộ lọc tùy chỉnh để đơn giản hóa chức năng changelist_view. Đây là bộ lọc:

class MyModelStatusFilter(admin.SimpleListFilter):
    title = _('Status')
    parameter_name = 'status'

    def lookups(self, request, model_admin):  # Available Values / Status Codes etc..
        return (
            (8, _('All')),
            (0, _('Incomplete')),
            (5, _('Pending')),
            (6, _('Selected')),
            (7, _('Accepted')),
        )

    def choices(self, cl):  # Overwrite this method to prevent the default "All"
        from django.utils.encoding import force_text
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == force_text(lookup),
                'query_string': cl.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

    def queryset(self, request, queryset):  # Run the queryset based on your lookup values
        if self.value() is None:
            return queryset.filter(status=5)
        elif int(self.value()) == 0:
            return queryset.filter(status__lte=4)
        elif int(self.value()) == 8:
            return queryset.all()
        elif int(self.value()) >= 5:
            return queryset.filter(status=self.value())
        return queryset.filter(status=5)

Và changelist_view bây giờ chỉ chuyển tham số mặc định nếu không có tham số nào. Ý tưởng là loại bỏ khả năng của bộ lọc chung chung để xem tất cả bằng cách sử dụng tham số no get. Để xem tất cả, tôi đã gán trạng thái = 8 cho mục đích đó:

class MyModelAdmin(admin.ModelAdmin):   

    ...

    list_filter = ('status', )

    def changelist_view(self, request, extra_context=None):
        if len(request.GET) == 0:
            get_param = "status=5"
            return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
        return super(MyModelAdmin, self).changelist_view(request, extra_context=extra_context)

Tôi có một bản sửa lỗi cho cảnh báo trước của mình, một bộ lọc tùy chỉnh. Tôi sẽ trình bày nó như một giải pháp thay thế.
radtek

Cảm ơn bạn, tôi thấy chuyển hướng là giải pháp sạch sẽ và đơn giản nhất. Tôi cũng không hiểu "lời báo trước". Tôi luôn nhận được kết quả mong muốn, cho dù bằng cách nhấp vào hoặc sử dụng liên kết trực tiếp (tôi không sử dụng bộ lọc tùy chỉnh).
Dennis Golomazov

6
def changelist_view( self, request, extra_context = None ):
    default_filter = False
    try:
        ref = request.META['HTTP_REFERER']
        pinfo = request.META['PATH_INFO']
        qstr = ref.split( pinfo )

        if len( qstr ) < 2:
            default_filter = True
    except:
        default_filter = True

    if default_filter:
        q = request.GET.copy()
        q['registered__exact'] = '1'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()

    return super( InterestAdmin, self ).changelist_view( request, extra_context = extra_context )

4

Bạn chỉ cần sử dụng return queryset.filter()hoặc if self.value() is Nonevà ghi đè phương thức SimpleListFilter

from django.utils.encoding import force_text

def choices(self, changelist):
    for lookup, title in self.lookup_choices:
        yield {
            'selected': force_text(self.value()) == force_text(lookup),
            'query_string': changelist.get_query_string(
                {self.parameter_name: lookup}, []
            ),
            'display': title,
        }

3

Lưu ý rằng nếu thay vì chọn trước một giá trị bộ lọc mà bạn muốn luôn lọc trước dữ liệu trước khi hiển thị nó trong quản trị viên, bạn nên ghi đè ModelAdmin.queryset()phương pháp đó.


Đây là một giải pháp khá sạch sẽ và nhanh chóng mặc dù nó vẫn có thể gây ra sự cố. Khi các tùy chọn lọc được bật trong quản trị viên, người dùng có thể nhận được kết quả dường như không chính xác. Nếu bộ truy vấn ghi đè có chứa mệnh đề .exclude () thì các bản ghi bị bắt bởi điều đó sẽ không bao giờ được liệt kê nhưng các tùy chọn lọc quản trị viên để hiển thị rõ ràng chúng sẽ vẫn được giao diện người dùng quản trị cung cấp.
Tomas Andrle,

Có nhiều câu trả lời khác đúng hơn với số phiếu thấp hơn áp dụng cho tình huống này vì OP đã yêu cầu rõ ràng rằng ông ấy sẽ đặt một bộ lọc trong đó bộ truy vấn sẽ là giải pháp sai như @TomasAndrle đã chỉ ra ở trên.
eskhool

Cảm ơn bạn đã chỉ ra điều này @eskhool, tôi đã cố gắng phản đối câu trả lời của mình về 0 nhưng có vẻ như nó không được phép phản đối bản thân.
akaihola

3

Một chút cải thiện cho câu trả lời của Greg bằng cách sử dụng DjangoChoices, Python> = 2.5 và tất nhiên Django> = 1.4.

from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter

class OrderStatusFilter(SimpleListFilter):
    title = _('Status')

    parameter_name = 'status__exact'
    default_status = OrderStatuses.closed

    def lookups(self, request, model_admin):
        return (('all', _('All')),) + OrderStatuses.choices

    def choices(self, cl):
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == lookup if self.value() else lookup == self.default_status,
                'query_string': cl.get_query_string({self.parameter_name: lookup}, []),
                'display': title,
            }

    def queryset(self, request, queryset):
        if self.value() in OrderStatuses.values:
            return queryset.filter(status=self.value())
        elif self.value() is None:
            return queryset.filter(status=self.default_status)


class Admin(admin.ModelAdmin):
    list_filter = [OrderStatusFilter] 

Cảm ơn Greg vì giải pháp tốt đẹp!


2

Tôi biết đó không phải là giải pháp tốt nhất, nhưng tôi đã thay đổi index.html trong mẫu quản trị, dòng 25 và 37 như sau:

25: <th scope="row"><a href="{{ model.admin_url }}{% ifequal model.name "yourmodelname" %}?yourflag_flag__exact=1{% endifequal %}">{{ model.name }}</a></th>

37: <td><a href="{{ model.admin_url }}{% ifequal model.name "yourmodelname" %}?yourflag__exact=1{% endifequal %}" class="changelink">{% trans 'Change' %}</a></td>


1

Tôi đã phải thực hiện một sửa đổi để bộ lọc hoạt động chính xác. Giải pháp trước đó đã làm việc cho tôi khi trang được tải. Nếu một 'hành động' được thực hiện, bộ lọc sẽ trở về 'Tất cả' chứ không phải mặc định của tôi. Giải pháp này tải trang thay đổi quản trị viên bằng bộ lọc mặc định, nhưng cũng duy trì các thay đổi bộ lọc hoặc bộ lọc hiện tại khi hoạt động khác xảy ra trên trang. Tôi chưa kiểm tra tất cả các trường hợp, nhưng trên thực tế, nó có thể giới hạn việc thiết lập bộ lọc mặc định chỉ xảy ra khi trang tải.

def changelist_view(self, request, extra_context=None):
    default_filter = False

    try:
        ref = request.META['HTTP_REFERER']
        pinfo = request.META['PATH_INFO']
        qstr = ref.split(pinfo)
        querystr = request.META['QUERY_STRING']

        # Check the QUERY_STRING value, otherwise when
        # trying to filter the filter gets reset below
        if querystr is None:
            if len(qstr) < 2 or qstr[1] == '':
                default_filter = True
    except:
        default_filter = True

    if default_filter:
        q = request.GET.copy()
        q['registered__isnull'] = 'True'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()

    return super(MyAdmin, self).changelist_view(request, extra_context=extra_context)

1

Một chút lạc đề nhưng tìm kiếm của tôi cho một câu hỏi tương tự đã dẫn tôi đến đây. Tôi đang tìm cách có một truy vấn mặc định theo ngày (tức là nếu không có đầu vào nào được cung cấp, chỉ hiển thị các đối tượng có timestampcủa 'Hôm nay'), điều này làm phức tạp câu hỏi một chút. Đây là những gì tôi nghĩ ra:

from django.contrib.admin.options import IncorrectLookupParameters
from django.core.exceptions import ValidationError

class TodayDefaultDateFieldListFilter(admin.DateFieldListFilter):
    """ If no date is query params are provided, query for Today """

    def queryset(self, request, queryset):
        try:
            if not self.used_parameters:
                now = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
                self.used_parameters = {
                    ('%s__lt' % self.field_path): str(now + datetime.timedelta(days=1)),
                    ('%s__gte' % self.field_path): str(now),
                }
                # Insure that the dropdown reflects 'Today'
                self.date_params = self.used_parameters
            return queryset.filter(**self.used_parameters)
        except ValidationError, e:
            raise IncorrectLookupParameters(e)

class ImagesAdmin(admin.ModelAdmin):
    list_filter = (
        ('timestamp', TodayDefaultDateFieldListFilter),
    )

Đây là một ghi đè đơn giản của mặc định DateFieldListFilter. Bằng cách cài đặt self.date_params, nó đảm bảo rằng trình đơn thả xuống của bộ lọc sẽ cập nhật thành bất kỳ tùy chọn nào phù hợp với self.used_parameters. Vì lý do này, bạn phải đảm bảo rằng đó self.used_parameterslà chính xác những gì sẽ được sử dụng bởi một trong những lựa chọn thả xuống đó (tức là, tìm hiểu điều gì date_paramssẽ xảy ra khi sử dụng 'Hôm nay' hoặc '7 ngày qua' và xây dựng self.used_parametersđể khớp với những lựa chọn đó).

Điều này được xây dựng để hoạt động với Django 1.4.10


1

Đây có thể là một chủ đề cũ, nhưng tôi nghĩ tôi sẽ thêm giải pháp của mình vì tôi không thể tìm thấy câu trả lời tốt hơn trên các tìm kiếm của google.

Làm những gì (không chắc liệu Deminic Rodger của nó, hoặc ha22109) được trả lời trong ModelAdmin cho changelist_view

class MyModelAdmin(admin.ModelAdmin):   
    list_filter = (CustomFilter,)

    def changelist_view(self, request, extra_context=None):

        if not request.GET.has_key('decommissioned__exact'):

            q = request.GET.copy()
            q['decommissioned__exact'] = 'N'
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

Sau đó, chúng ta cần tạo một SimpleListFilter tùy chỉnh

class CustomFilter(admin.SimpleListFilter):
    title = 'Decommissioned'
    parameter_name = 'decommissioned'  # i chose to change it

def lookups(self, request, model_admin):
    return (
        ('All', 'all'),
        ('1', 'Decommissioned'),
        ('0', 'Active (or whatever)'),
    )

# had to override so that we could remove the default 'All' option
# that won't work with our default filter in the ModelAdmin class
def choices(self, cl):
    yield {
        'selected': self.value() is None,
        'query_string': cl.get_query_string({}, [self.parameter_name]),
        # 'display': _('All'),
    }
    for lookup, title in self.lookup_choices:
        yield {
            'selected': self.value() == lookup,
            'query_string': cl.get_query_string({
                self.parameter_name: lookup,
            }, []),
            'display': title,
        }

def queryset(self, request, queryset):
    if self.value() == '1':
        return queryset.filter(decommissioned=1)
    elif self.value() == '0':
        return queryset.filter(decommissioned=0)
    return queryset

Tôi thấy mình cần phải sử dụng hàm 'force_text' (còn gọi là force_unicode) trong lệnh gọi lợi nhuận trong hàm lựa chọn, nếu không tùy chọn bộ lọc đã chọn sẽ không hiển thị là 'đã chọn'. Đó là "" đã chọn ": self.value () == force_text (tra cứu),"
MagicLAMP

1

Đây là phiên bản Sạch nhất mà tôi có thể tạo bộ lọc với 'Tất cả' được xác định lại và giá trị Mặc định được chọn.

Nếu hiển thị cho tôi theo mặc định Các chuyến đi hiện đang diễn ra.

class HappeningTripFilter(admin.SimpleListFilter):
    """
    Filter the Trips Happening in the Past, Future or now.
    """
    default_value = 'now'
    title = 'Happening'
    parameter_name = 'happening'

    def lookups(self, request, model_admin):
        """
        List the Choices available for this filter.
        """
        return (
            ('all', 'All'),
            ('future', 'Not yet started'),
            ('now', 'Happening now'),
            ('past', 'Already finished'),
        )

    def choices(self, changelist):
        """
        Overwrite this method to prevent the default "All".
        """
        value = self.value() or self.default_value
        for lookup, title in self.lookup_choices:
            yield {
                'selected': value == force_text(lookup),
                'query_string': changelist.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

    def queryset(self, request, queryset):
        """
        Returns the Queryset depending on the Choice.
        """
        value = self.value() or self.default_value
        now = timezone.now()
        if value == 'future':
            return queryset.filter(start_date_time__gt=now)
        if value == 'now':
            return queryset.filter(start_date_time__lte=now, end_date_time__gte=now)
        if value == 'past':
            return queryset.filter(end_date_time__lt=now)
        return queryset.all()

0

Đã tạo một lớp con Bộ lọc có thể tái sử dụng, lấy cảm hứng từ một số câu trả lời ở đây (chủ yếu là của Greg).

Ưu điểm:

Có thể tái sử dụng - Có thể lắp vào bất kỳ ModelAdminlớp tiêu chuẩn nào

Có thể mở rộng - Dễ dàng thêm logic bổ sung / tùy chỉnh để QuerySetlọc

Dễ sử dụng - Ở dạng cơ bản nhất, chỉ một thuộc tính tùy chỉnh và một phương thức tùy chỉnh cần được triển khai (ngoài những thuộc tính cần thiết cho phân lớp SimpleListFilter)

Quản trị viên trực quan - Liên kết bộ lọc "Tất cả" đang hoạt động như mong đợi; cũng như tất cả những người khác

Không có chuyển hướng - Không cần phải kiểm tra GETtải trọng yêu cầu, không xác định được HTTP_REFERER(hoặc bất kỳ nội dung liên quan đến yêu cầu nào khác, ở dạng cơ bản)

Không có (danh sách thay đổi) thao tác xem - Và không có thao tác khuôn mẫu (trời cấm)

Mã:

(hầu hết các imports chỉ dành cho gợi ý loại và ngoại lệ)

from typing import List, Tuple, Any

from django.contrib.admin.filters import SimpleListFilter
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.views.main import ChangeList
from django.db.models.query import QuerySet
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError


class PreFilteredListFilter(SimpleListFilter):

    # Either set this or override .get_default_value()
    default_value = None

    no_filter_value = 'all'
    no_filter_name = _("All")

    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = None

    # Parameter for the filter that will be used in the URL query.
    parameter_name = None

    def get_default_value(self):
        if self.default_value is not None:
            return self.default_value
        raise NotImplementedError(
            'Either the .default_value attribute needs to be set or '
            'the .get_default_value() method must be overridden to '
            'return a URL query argument for parameter_name.'
        )

    def get_lookups(self) -> List[Tuple[Any, str]]:
        """
        Returns a list of tuples. The first element in each
        tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        """
        raise NotImplementedError(
            'The .get_lookups() method must be overridden to '
            'return a list of tuples (value, verbose value).'
        )

    # Overriding parent class:
    def lookups(self, request, model_admin) -> List[Tuple[Any, str]]:
        return [(self.no_filter_value, self.no_filter_name)] + self.get_lookups()

    # Overriding parent class:
    def queryset(self, request, queryset: QuerySet) -> QuerySet:
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        if self.value() is None:
            return self.get_default_queryset(queryset)
        if self.value() == self.no_filter_value:
            return queryset.all()
        return self.get_filtered_queryset(queryset)

    def get_default_queryset(self, queryset: QuerySet) -> QuerySet:
        return queryset.filter(**{self.parameter_name: self.get_default_value()})

    def get_filtered_queryset(self, queryset: QuerySet) -> QuerySet:
        try:
            return queryset.filter(**self.used_parameters)
        except (ValueError, ValidationError) as e:
            # Fields may raise a ValueError or ValidationError when converting
            # the parameters to the correct type.
            raise IncorrectLookupParameters(e)

    # Overriding parent class:
    def choices(self, changelist: ChangeList):
        """
        Overridden to prevent the default "All".
        """
        value = self.value() or force_str(self.get_default_value())
        for lookup, title in self.lookup_choices:
            yield {
                'selected': value == force_str(lookup),
                'query_string': changelist.get_query_string({self.parameter_name: lookup}),
                'display': title,
            }

Ví dụ sử dụng đầy đủ:

from django.contrib import admin
from .models import SomeModelWithStatus


class StatusFilter(PreFilteredListFilter):
    default_value = SomeModelWithStatus.Status.FOO
    title = _('Status')
    parameter_name = 'status'

    def get_lookups(self):
        return SomeModelWithStatus.Status.choices


@admin.register(SomeModelWithStatus)
class SomeModelAdmin(admin.ModelAdmin):
    list_filter = (StatusFilter, )

Hy vọng điều này sẽ giúp ai đó; phản hồi luôn được đánh giá cao.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.