2009-06-14 22 views
72

मैं django व्यवस्थापक (एक मॉडल डैशबोर्ड के दाईं ओर दिखाई देने वाले फ़िल्टर) में एक कस्टम फ़िल्टर कैसे जोड़ सकता हूं? मैं जानता हूँ कि अपनी आसान इस तरह एक "गणना" क्षेत्र के बारे में एक फिल्टर है कि मॉडल का एक क्षेत्र के आधार पर है, लेकिन क्या शामिल करने के लिए:Django पर Django व्यवस्थापक में कस्टम फ़िल्टर 1.3 या

class NewsItem(models.Model): 
    headline = models.CharField(max_length=4096, blank=False) 
    byline_1 = models.CharField(max_length=4096, blank=True) 
    dateline = models.DateTimeField(help_text=_("date/time that appears on article")) 
    body_copy = models.TextField(blank=False) 

    when_to_publish = models.DateTimeField(verbose_name="When to publish", blank=True, null=True) 

    # HOW CAN I HAVE "is_live" as part of the admin filter? It's a calculated state!! 
    def is_live(self): 
     if self.when_to_publish is not None: 
      if (self.when_to_publish < datetime.now()): 
       return """ <img alt="True" src="/media/img/admin/icon-yes.gif"/> """ 
     else: 
      return """ <img alt="False" src="/media/img/admin/icon-no.gif"/> """  

    is_live.allow_tags = True 

class NewsItemAdmin(admin.ModelAdmin): 
    form = NewsItemAdminForm 
    list_display = ('headline', 'id', 'is_live') 
    list_filter = ('is_live') # how can i make this work?? 
+0

अन्य लोगों को मदद कर सकता है ने कहा कि इस सुविधा ट्रंक (1.4 देव) में है। कुछ और जानकारी: [रिलीज नोट] (https://code.djangoproject.com/browser/django/trunk/docs/releases/1.4.txt?rev=16144#L40) और [दस्तावेज़] (https: // कोड। djangoproject.com/browser/django/trunk/docs/ref/contrib/admin/index.txt#L604)। – Paolo

+1

यहां प्रलेखन के लिए एक बेहतर लिंक है; SimpleListFilter को विस्तारित करने का तरीका यहां जाना है। फ़िल्टरस्पेक्स पुराना है। https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter – fastmultiplication

+0

देखें [मैटल उत्तर] (https://stackoverflow.com/a/6355234/) आधिकारिक दस्तावेज के लिंक के साथ नीचे। –

उत्तर

57

धन्यवाद मुझे इस लागू करने के लिए सही दिशा में धक्का देने के लिए gpilotino करने के लिए।

मैंने देखा कि प्रश्न का कोड एक लाइवटाइम का उपयोग कर रहा है जब यह पता चलता है कि यह कब रहता है। इसलिए मैंने डेटफिल्डफिल्टरस्पेक का उपयोग किया और इसे उप-वर्गीकृत किया।

from django.db import models 
from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec,DateFieldFilterSpec 
from django.utils.encoding import smart_unicode 
from django.utils.translation import ugettext as _ 
from datetime import datetime 

class IsLiveFilterSpec(DateFieldFilterSpec): 
    """ 
    Adds filtering by future and previous values in the admin 
    filter sidebar. Set the is_live_filter filter in the model field attribute 
    'is_live_filter'. my_model_field.is_live_filter = True 
    """ 

    def __init__(self, f, request, params, model, model_admin): 
     super(IsLiveFilterSpec, self).__init__(f, request, params, model, 
               model_admin) 
     today = datetime.now() 
     self.links = (
      (_('Any'), {}), 
      (_('Yes'), {'%s__lte' % self.field.name: str(today), 
         }), 
      (_('No'), {'%s__gte' % self.field.name: str(today), 
        }), 

     ) 


    def title(self): 
     return "Is Live" 

# registering the filter 
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'is_live_filter', False), 
           IsLiveFilterSpec)) 

उपयोग करने के लिए आप एक filters.py में उपरोक्त कोड डाल सकते हैं, और मॉडल आप

+2

क्या आप इस कोड के साथ क्या करते हैं इसके अंतिम भाग पर आप थोड़ा और विस्तार कर सकते हैं? –

+0

Rosarch, कोड की अंतिम पंक्ति मॉडल कक्षा में अपने models.py में Django में is_live_filter पंजीकृत करता है, तो कहते हैं कि अनुच्छेद, आप एक क्षेत्र PUBLISH_DATE कहा जाता है आप –

+1

अंतिम पंक्ति * filter_specs.insert publish_date.is_live_filter कहेंगे है * है की सुविधा देता है बहुत महत्वपूर्ण है, अन्यथा आपका कस्टम फ़िल्टर शायद दिखाई नहीं देगा, उस फ़ील्ड प्रकार के लिए अंतर्निहित फ़िल्टरपेक्स में से एक इसके बजाए दिखाएगा। (मैंने पहले जवाब सही ढंग से नहीं पढ़ा था और अंतर्निहित फ़िल्टरपेक्स जैसे .register विधि का उपयोग कर रहा था!) ​​ – Anentropic

3

आप नहीं कर सकते हैं, दुर्भाग्य से। वर्तमान में गैर-फ़ील्ड आइटमों को list_filter प्रविष्टियों के रूप में उपयोग नहीं किया जा सकता है। ('is_live',)

+4

someday mabye, यह एक खुला टिकट है http://code.djangoproject.com/ticket/5833 – imjoevasquez

+2

FWIW, # 5833 के लिए एक फिक्स अब django 1.4 –

22

आप एक कस्टम FilterSpec (कहीं भी documentend नहीं) लिखने के लिए है:

ध्यान रखें कि आपके व्यवस्थापक वर्ग भी काम नहीं किया होगा अगर यह एक क्षेत्र था, एक एकल आइटम टपल के रूप में अल्पविराम की जरूरत है। एक उदाहरण के लिए यहाँ देखो:

http://www.djangosnippets.org/snippets/1051/

+1

संबंधित स्निपेट के लिए django ट्रंक में है: http://djangosnippets.org/snippets/1 9 63/ – Eddified

9

करने के लिए फिल्टर जोड़ने के लिए वर्तमान Django विकास संस्करण में चाहते हैं में आयात कस्टम फ़िल्टर के लिए समर्थन नहीं है : https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter

+1

देखें और अधिक विशिष्ट होने के लिए: https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django .contrib.admin.ModelAdmin.list_filter – Webthusiast

+1

@Webthusiast इसे सुधारने के लिए किसी भी उत्तर को संपादित करने के लिए स्वतंत्र महसूस करें। इस मामले में, मैंने पहले ही उत्तर में अपना अधिक विशिष्ट यूआरएल शामिल कर लिया है। –

2

उपयोगकर्ता कुछ देशों को मुफ्त में सामान प्रदान करता है। सभी देशों, हाँ - - डाक मुक्त, नहीं - आरोप लगाया डाक

सभी: मैं उन देशों फिल्टर करने के लिए करना चाहता था।

इस प्रश्न का मुख्य उत्तर मेरे लिए काम नहीं करता (Django 1.3) मुझे लगता है क्योंकि __init__ विधि में कोई field_path पैरामीटर प्रदान नहीं किया गया था। इसके अलावा यह DateFieldFilterSpec उपclassed। postage क्षेत्र एक FloatField

from django.contrib.admin.filterspecs import FilterSpec 

class IsFreePostage(FilterSpec): 

    def __init__(self, f, request, params, model, model_admin, field_path=None): 
     super(IsFreePostage, self).__init__(f, request, params, model, 
      model_admin, field_path) 

     self.removes = { 
      'Yes': ['postage__gt'], 
      'No': ['postage__exact'], 
      'All': ['postage__exact', 'postage__gt'] } 

     self.links = (
      ('All', {}), 
      ('Yes', {'postage__exact': 0}), 
      ('No', {'postage__gt': 0})) 

     if request.GET.has_key('postage__exact'): 
      self.ttl = 'Yes' 
     elif request.GET.has_key('postage__gt'): 
      self.ttl = 'No' 
     else: 
      self.ttl = 'All' 

    def choices(self, cl): 
     for title, param_dict in self.links: 
      yield {'selected': title == self.ttl, 
        'query_string': cl.get_query_string(param_dict, 
         self.removes[title]), 
        'display': title} 
    def title(self): 
     return 'Free Postage' 

FilterSpec.filter_specs.insert(0, 
    (lambda f: getattr(f, 'free_postage', False), IsFreePostage)) 

self.links हम dicts की आपूर्ति है। प्रत्येक संभावित फ़िल्टर के लिए ?postage__exact=0 जैसे HTTP क्वेरी स्ट्रिंग बनाने के लिए उपयोग किया जाता है। फ़िल्टर मुझे लगता है कि संचयी हैं इसलिए यदि 'नो' के लिए पिछले अनुरोध था और अब हमारे पास 'हां' के लिए अनुरोध है तो हमें 'नहीं' क्वेरी को हटाना होगा। self.removes निर्दिष्ट करता है कि प्रत्येक क्वेरी के लिए क्या निकालना चाहिए। choices विधि क्वेरी स्ट्रिंग्स का निर्माण करती है, कहती है कि कौन सा फ़िल्टर चुना गया है और फ़िल्टर का प्रदर्शित नाम सेट करता है।

3

बस एक sidenote: आप deafult उपयोग कर सकते हैं इस तरह और अधिक आसानी से Django व्यवस्थापक पर टिक्स:

def is_live(self): 
    if self.when_to_publish is not None: 
     if (self.when_to_publish < datetime.now()): 
      return True 
    else: 
     return False 

is_live.boolean = True 
3

नहीं सबसे अनुकूल तरीके (सीपीयू के लिहाज से), लेकिन सरल और काम करेंगे, इसलिए मैं इसे इस तरह करते हैं (मेरे छोटे डेटाबेस के लिए)। मेरा Django संस्करण 1.6 है।

व्यवस्थापक में।py:

class IsLiveFilter(admin.SimpleListFilter): 
    title = 'Live' 
    parameter_name = 'islive' 
    def lookups(self, request, model_admin): 
     return (
      ('1', 'islive'), 
     ) 
    def queryset(self, request, queryset): 
     if self.value(): 
      array = [] 
      for element in queryset: 
       if element.is_live.__call__() == True: 
        q_array.append(element.id) 
      return queryset.filter(pk__in=q_array) 

...

class NewsItemAdmin(admin.ModelAdmin): 
    form = NewsItemAdminForm 
    list_display = ('headline', 'id', 'is_live') 
    list_filter = (IsLiveFilter) 

कुंजी यहाँ विचार के माध्यम से __call __() समारोह एक क्वेरीसमूह में कस्टम फ़ील्ड का उपयोग करने की है।

+0

शायद सबसे अनुकूलित तरीका नहीं है, लेकिन एक सीधा और कामकाजी वाला है। यह मुझे सिरदर्द बचाया। – d6bels

1

यहाँ जवाब है और यथासंभव सरल कस्टम फ़िल्टर लागू किया यह पहले से ही

Django admin date range filter

संबंधित मुद्दे