Django व्यवस्थापक में डिफ़ॉल्ट फ़िल्टर


94

मैं 'ALL' से डिफ़ॉल्ट फ़िल्टर विकल्प कैसे बदल सकता हूँ? मैं एक क्षेत्र के रूप में नामित किया है statusजो तीन मूल्य हैं: activate, pendingऔर rejected। जब मैं list_filterDjango के व्यवस्थापक का उपयोग करता हूं , तो फ़िल्टर डिफ़ॉल्ट रूप से 'सभी' पर सेट होता है, लेकिन मैं इसे डिफ़ॉल्ट रूप से लंबित करना चाहता हूं।

जवाबों:


102

इसे प्राप्त करने के लिए और आपके साइडबार में एक प्रयोग करने योग्य 'ऑल' लिंक है (यानी जो लंबित दिखाने के बजाय सभी दिखाता है), आपको एक कस्टम सूची फ़िल्टर बनाने की आवश्यकता होगी, django.contrib.admin.filters.SimpleListFilterजिसे डिफ़ॉल्ट रूप से 'लंबित' से फ़िल्टर किया जा सकता है। इन लाइनों के साथ कुछ काम करना चाहिए:

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] 

संपादित करें: Django 1.4 की आवश्यकता है (धन्यवाद साइमन)


3
यह सभी का सबसे साफ समाधान है, फिर भी इसमें सबसे कम उठाव है ... इसके लिए Django 1.4 की आवश्यकता है, हालांकि, यह अब तक दिया जाना चाहिए।
साइमन

@Greg आप व्यवस्थापक पृष्ठ से फ़िल्टर और फ़िल्टर टैब की कार्यक्षमता को पूरी तरह से कैसे हटाते हैं ?


2
इस समाधान में एक छोटी सी खामी है। जब फ़िल्टर खाली होता है (वास्तव में 'लंबित' फ़िल्टर का उपयोग किया जाता है), तो Django 1.8 गलत तरीके से पूर्ण परिणाम की गणना निर्धारित करता है और अगर शो_फुल_सेरल_काउंट सही है (डिफ़ॉल्ट रूप से) तो परिणाम की गिनती न दिखाएं । -
अलेक्जेंडर फेडोटोव

ध्यान दें कि यदि आप choicesसमाधान में विधि को ओवरराइड करने में विफल रहते हैं, तो यह विकल्प की सूची में सबसे ऊपर अपना ऑल ऑप्शन जोड़ना होगा ।
रिछार्ड

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
इस समाधान में यह खामी है कि यद्यपि यूआई में "ऑल" पसंद अभी भी प्रदर्शित है, यह चयन करते हुए अभी भी डिफ़ॉल्ट फ़िल्टरिंग लागू होता है।
एकैहोला

मैं एक ही सवाल है, लेकिन मैं पुनरावृत्ति ... खेद im Django के साथ नए समझ सकता हूँ ... लेकिन शायद इस वसीयत काम blog.dougalmatthews.com/2008/10/...
Asinox

यह अच्छा है, लेकिन मुझे url में प्राप्त पैरामीटर को देखने की आवश्यकता है ताकि मेरा फ़िल्टर इसे उठा सके और इसे चयनित दिखा सके। शीघ्र ही मेरा समाधान पोस्ट करना।
रेडटेक

स्पष्टीकरण गायब है। सिर्फ कोड का एक टुकड़ा पोस्ट करने से सभी को मदद नहीं मिल सकती है। इसके शीर्ष पर यह काम नहीं कर रहा है और एक छोटे से संदर्भ के बिना यह पता लगाना मुश्किल है कि क्यों
EvilSmurf

19

ऊपर ha22109 के उत्तर को लिया HTTP_REFERERऔर तुलना करके "ऑल" के चयन की अनुमति देने के लिए संशोधित किया गया PATH_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
यह मेरे लिए टूट गया क्योंकि HTTP_REFERER हमेशा मौजूद नहीं था। मैंने 'referer = request.META.get (' HTTP_REFERER ',' ') किया; परीक्षण = referer.split (request.META ['PATH_INFO']) `
बेन लेखक

@ जब मैं आपकी दो पंक्तियों रेफर = request.META.get ('HTTP_REFERER', '') परीक्षण = referer.split (request.META ['PATH_INFO]] का उपयोग कर रहा हूँ। मैं HTTP_REFERER के बारे में बहुत कुछ नहीं करता। यदि HTTP_REFERER मौजूद नहीं है, तो क्या समस्या इन पंक्तियों से पूरी तरह से ठीक हो गई है।
the_game

@the_game हाँ, यह विचार है कि यदि आप किसी वर्ग की कुंजी का उपयोग करने का प्रयास करते हैं जो मौजूद नहीं है, तो यह फेंकता है KeyError, यदि आप उस तानाशाही get()विधि का उपयोग करते हैं जिसे आप डिफ़ॉल्ट रूप से निर्दिष्ट कर सकते हैं। मैंने खाली-स्ट्रिंग का एक डिफ़ॉल्ट निर्दिष्ट किया ताकि विभाजन () फेंक न जाए AttributeError। बस इतना ही।
बेन लेखक

@Ben। यह मेरे लिए काम करता है। आप इस सवाल का जवाब भी दे सकते हैं, मेरा मानना ​​है कि यह इस सवाल का एक विस्तार है केवल stackoverflow.com/questions/10410982/… । क्या आप मुझे इसके लिए कोई समाधान प्रदान कर सकते हैं।
the_game

1
यह अच्छा काम करता है। हालांकि, के has_key()पक्ष में पदावनत किया जाता है key in d। लेकिन मुझे पता है कि आपने सिर्फ ha22109 के जवाब से लिया था। एक प्रश्न: request.META['PATH_INFO']जब आप सिर्फ request.path_info(कम) का उपयोग कर सकते हैं तो क्यों उपयोग करें ?
निक

19

मुझे पता है कि यह प्रश्न अभी काफी पुराना है, लेकिन यह अभी भी मान्य है। मेरा मानना ​​है कि यह ऐसा करने का सबसे सही तरीका है। यह अनिवार्य रूप से ग्रेग की विधि के समान है, लेकिन आसान पुन: उपयोग के लिए एक विस्तार योग्य वर्ग के रूप में तैयार किया गया है।

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

यहां पुनर्निर्देशन का उपयोग करके मेरा जेनेरिक समाधान है, यह सिर्फ जांचता है कि क्या कोई जीईटी पैरामीटर हैं, यदि कोई मौजूद नहीं है तो यह डिफ़ॉल्ट रूप से पैरामीटर के साथ पुनर्निर्देशित करता है। मेरे पास एक list_filter सेट है, इसलिए यह उठाता है और डिफ़ॉल्ट प्रदर्शित करता है।

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)

एकमात्र चेतावनी तब होती है जब आप ""? url में मौजूद है, कोई HTTP_REFERER सेट नहीं है इसलिए यह डिफ़ॉल्ट पैरामीटर और रीडायरेक्ट का उपयोग करेगा। यह मेरे लिए ठीक है, यह बहुत अच्छा काम करता है जब आप व्यवस्थापक फ़िल्टर के माध्यम से क्लिक करते हैं।

अद्यतन :

कैविएट के चारों ओर जाने के लिए, मैंने एक कस्टम फ़िल्टर फंक्शन लिखना शुरू किया, जिसने चेंजलिस्ट_व्यू फंक्शनालिटी को सरल बनाया। यहाँ फिल्टर है:

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)

और चैंजस्टिस्ट_व्यू अब केवल डिफ़ॉल्ट पैरामीटर पास करता है यदि कोई भी मौजूद नहीं है। यह विचार था कि जेनरेटर फिल्टर की क्षमता से छुटकारा पाने के लिए सभी को बिना किसी मापदण्ड का उपयोग किए देखना होगा। सभी को देखने के लिए मैंने उस उद्देश्य के लिए = 8 का दर्जा दिया है।

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)

मेरे पास मेरे कैविएट के लिए एक फिक्स है, एक कस्टम फ़िल्टर है। मैं इसे एक वैकल्पिक समाधान के रूप में प्रस्तुत करूंगा।
रेडटेक

धन्यवाद, मुझे लगता है कि पुनर्निर्देश सबसे साफ और सरल समाधान है। मैं "कैविएट" भी नहीं समझता। मुझे हमेशा वांछित परिणाम मिलता है, चाहे प्रत्यक्ष लिंक पर क्लिक करके या उपयोग करके (मैंने कस्टम फ़िल्टर का उपयोग नहीं किया)।
डेनिस गोलोमेज़ोव

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

आप बस SimpleListFilter की विधि का उपयोग return queryset.filter()या if self.value() is Noneओवरराइड कर सकते हैं

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

ध्यान दें कि यदि फ़िल्टर मान को पूर्व-चयन करने के बजाय आप डेटा को व्यवस्थापक में दिखाने से पहले हमेशा फ़िल्टर करना चाहते हैं, तो आपको ModelAdmin.queryset()इसके बजाय विधि को ओवरराइड करना चाहिए ।


यह एक बहुत साफ और त्वरित समाधान है, हालांकि यह अभी भी समस्याएं पैदा कर सकता है। जब व्यवस्थापक में फ़िल्टरिंग विकल्प सक्षम होते हैं तो उपयोगकर्ता को गलत परिणाम मिल सकते हैं। यदि ओवरराइड क्वेरीज़ में एक .exclude () क्लॉज़ होता है, तो उसके द्वारा पकड़े गए रिकॉर्ड को कभी सूचीबद्ध नहीं किया जाएगा, लेकिन उन्हें स्पष्ट रूप से दिखाने के लिए व्यवस्थापक फ़िल्टरिंग विकल्प अभी भी व्यवस्थापक UI द्वारा प्रस्तुत किए जाएंगे।
टॉमस एंड्रेल

निचले वोटों के साथ अन्य सही उत्तर हैं जो इस स्थिति पर लागू होते हैं क्योंकि ओपी ने स्पष्ट रूप से अनुरोध किया है कि वह एक फिल्टर लगाने जा रहा है जिसमें एक क्वेरी गलत समाधान होगी जैसा कि @TomasAndrle द्वारा ऊपर बताया गया है।
eskhool

@Eskhool को इंगित करने के लिए धन्यवाद, मैंने अपने उत्तर को शून्य करने की कोशिश की, लेकिन ऐसा लगता है कि इसे स्वयं को नीचा दिखाने की अनुमति नहीं है।
एकैहोला

3

DjangoChoices, Python> = 2.5 और निश्चित रूप से 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] 

अच्छा समाधान के लिए ग्रेग को धन्यवाद!


2

मुझे पता है कि यह सबसे अच्छा समाधान नहीं है, लेकिन मैंने इस तरह से व्यवस्थापक टेम्पलेट, लाइन 25 और 37 में index.html को बदल दिया है:

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

मुझे सही ढंग से काम करने के लिए फ़िल्टरिंग प्राप्त करने के लिए एक संशोधन करना पड़ा। जब पृष्ठ लोड हुआ तो मेरे लिए पिछले समाधान ने काम किया। यदि कोई 'एक्शन' किया गया था, तो फ़िल्टर 'ऑल' पर वापस चला गया था और मेरी डिफ़ॉल्ट नहीं था। यह समाधान डिफ़ॉल्ट फ़िल्टर के साथ व्यवस्थापक परिवर्तन पृष्ठ को लोड करता है, लेकिन पृष्ठ पर अन्य गतिविधि होने पर फ़िल्टर परिवर्तन या वर्तमान फ़िल्टर को भी बनाए रखता है। मैंने सभी मामलों का परीक्षण नहीं किया है, लेकिन वास्तव में यह डिफ़ॉल्ट फ़िल्टर की सेटिंग को सीमित कर सकता है जब पृष्ठ लोड होता है।

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

थोड़ा ऑफ-टॉपिक लेकिन इसी तरह के प्रश्न के लिए मेरी खोज ने मुझे यहां पहुंचाया। मैं एक तिथि के आधार पर डिफ़ॉल्ट क्वेरी देखना चाहता था (अर्थात यदि कोई इनपुट प्रदान नहीं किया गया है, तो केवल timestamp'टुडे' के साथ ऑब्जेक्ट दिखाएँ ), जो प्रश्न को थोड़ा जटिल करता है। यहां वह है जो मैंने जुटाया:

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),
    )

यह डिफ़ॉल्ट का एक सरल ओवरराइड है DateFieldListFilter। सेटिंग से self.date_params, यह सुनिश्चित करता है कि फ़िल्टर ड्रॉपडाउन जो भी विकल्प से मेल खाता है, वह अपडेट हो जाएगा self.used_parameters। इस कारण से, आपको यह सुनिश्चित करना चाहिए कि self.used_parametersवास्तव में उन ड्रॉपडाउन चयनों में से एक का उपयोग क्या होगा (अर्थात, date_params'आज' या 'अंतिम 7 दिन' का उपयोग करते समय क्या होगा और self.used_parametersउन का मिलान करने के लिए निर्माण करें )।

यह Django 1.4.10 के साथ काम करने के लिए बनाया गया था


1

यह एक पुराना धागा हो सकता है, लेकिन मुझे लगा कि मैं अपना समाधान जोड़ूंगा क्योंकि मुझे Google खोजों पर बेहतर उत्तर नहीं मिल सके।

क्या करना है (यह सुनिश्चित नहीं है कि अगर इसकी डेमिनिक रॉजर, या ha22109) ने chanAdistist_view के लिए ModelAdmin में उत्तर दिया

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)

फिर हमें एक कस्टम SimpleListFilter बनाने की आवश्यकता है

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

मैंने पाया कि मुझे पसंद फ़ंक्शन में उपज कॉल में 'force_text' (उर्फ force_unicode) फ़ंक्शन का उपयोग करने की आवश्यकता है, अन्यथा चयनित फ़िल्टर विकल्प 'चयनित' के रूप में दिखाई नहीं देगा। वह "चयनित" है: self.value () == force_text (लुकअप), "
मैजिकलैम्प

1

यहां सबसे साफ संस्करण मैं एक पुनर्परिभाषित 'ऑल' के साथ एक फिल्टर उत्पन्न करने में सक्षम था और एक डिफ़ॉल्ट मान जिसे चुना गया है।

यदि वर्तमान में हो रहे डिफ़ॉल्ट रूप से मुझे दिखाता है।

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

यहाँ कुछ जवाबों (ज्यादातर ग्रेग) से प्रेरित एक पुन: प्रयोज्य फ़िल्टर उप-वर्ग बनाया गया।

लाभ:

पुन: प्रयोज्य - किसी भी मानक ModelAdminवर्गों में प्लग करने योग्य

विस्तार योग्य - QuerySetफ़िल्टर करने के लिए अतिरिक्त / कस्टम तर्क जोड़ना आसान है

उपयोग करने में आसान - इसके सबसे बुनियादी रूप में, केवल एक कस्टम विशेषता और एक कस्टम विधि को लागू करने की आवश्यकता है (इसके अलावा SimpleListFilter उपवर्ग के लिए आवश्यक)

सहज प्रशासन - "सभी" फ़िल्टर लिंक अपेक्षित रूप से काम कर रहा है; जैसा कि सभी अन्य हैं

कोई पुनर्निर्देश नहीं - इसके मूल रूप में GETअनुरोध पेलोड, अज्ञेय HTTP_REFERER(या किसी अन्य अनुरोध से संबंधित सामान,) का निरीक्षण करने की आवश्यकता नहीं है

नो (चेंजलिगिस्ट) व्यू हेरफेर - और नो टेम्प्लेट जोड़तोड़ (भगवान न करे)

कोड:

(अधिकांश imports सिर्फ टाइप संकेत और अपवाद के लिए हैं)

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,
            }

पूर्ण उपयोग उदाहरण:

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, )

आशा है कि यह किसी की मदद करता है; प्रतिक्रिया हमेशा सराहना की।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.