2009-11-03 15 views
14

Czy witryna administracyjna Django może wybierać pozycje według niestandardowego zakresu dat, tj. Używając dwóch DateFields z AdminDateWidget? Wiem, że istnieją właściwości date_hierarchy i list_filter, ale nie wydają się one bardzo przydatne, gdy istnieje wiele wpisów DB i trzeba tylko filtrować elementy według dokładnych zapytań date__gte i date__lte.Filtrowanie według niestandardowego zakresu dat w administratorze Django

Odpowiedz

20

Uwaga: Napisałem tę odpowiedź w 2009 roku, kiedy wymagana funkcjonalność nie była dostępna w Django jako publiczny interfejs API. W przypadku Django 1.4+ zobacz inne odpowiedzi.

Ta funkcja nie jest dostarczana, o ile wiem, ale można ją zbudować samodzielnie.

Po pierwsze, można filtrować elementy za pomocą date__gte i date__lte jako argumenty GET w adresie URL.

Na przykład

/admin/myapp/bar/?date__gte=2009-5-1&date__lt=2009-8-1 

wyświetli wszystkie obiekty kreskowe z datami w maju, czerwcu lub lipcu 2009 r

Następnie jeśli nadpisać plik admin/change_list.html szablonu można dodawać widżety dla dat rozpoczęcia i zakończenia , które prowadzą do wymaganego adresu URL.


Hat końcówka do Daniel's answer do innego SO pytanie, który nauczył mnie o użyciu parametrów filtrowania queryset GET argumentów.

+0

Bardzo dziękuję, bardzo przydatna funkcja. –

5

Klasa znaleźć na https://github.com/runekaagaard/django-admin-filtrateDateRangeFilter() właśnie to robi :)

+0

Wydaje się nie działać dla Django 1.4 –

+0

Nie testowany na 1.4, więc prawdopodobnie nie. Myślę, że w interfejsie 1.4 pojawił się nowy api filtrów administracyjnych, które mogłyby wstrząsnąć. –

3

skończyło się na wdrożenie go coś takiego:

# admin.py 
class FooAdmin(MyModelAdmin): 

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

     extra_context = extra_context or {} 
     try: 
      extra_context['trade_date_gte'] = request.GET['date__gte'] 
     except: 
      pass 

     try: 
      extra_context['trade_date_lte'] = request.GET['date__lte'] 
     except: 
      pass 

    return super(FileNoteAdmin, self).changelist_view(request, extra_context) 


# change_list.html 

{% extends "admin/admin/change_list.html" %} 
{% load i18n admin_static admin_list %} 
{% load url from future %} 
{% load admin_urls %} 


{% block filters %} 

{% if cl.has_filters %} 
    <div id="changelist-filter"> 
    <h2>{% trans 'Filter' %} </h2> 

<h3>By trade date</h3> 

<link href="/media/css/ui-lightness/jquery-ui-1.8.19.custom.css" rel="stylesheet" type="text/css"/> 
<script src="/media/js/jquery/jquery-min.js"></script> 
<script src="/media/js/jquery/jquery-ui-1.8.19.custom.min.js"></script> 

<script> 

    $(function() { 
     $("#trade_date_gte").datepicker({ dateFormat: 'yy-mm-dd'{% if trade_date_gte %}, defaultDate: '{{ trade_date_gte }}'{% endif %} }); 
     $("#trade_date_lte").datepicker({ dateFormat: 'yy-mm-dd'{% if trade_date_lte %}, defaultDate: '{{ trade_date_lte }}'{% endif %} }); 
    }); 

function applyDateFilters() { 

    qs = location.search; 

    if (qs.charAt(0) == '?') qs = qs.substring(1); 

    var qsComponents = qs.split(/[&;]/g); 

    new_qs = []; 
    for (var index = 0; index < qsComponents.length; index ++){ 

     var keyValuePair = qsComponents[index].split('='); 
     var key   = keyValuePair[0]; 
     var value  = keyValuePair[1]; 

     if(key == 'trade_date__gte' || key == 'trade_date__lte' || key == '') { 
      continue; 
     } else { 
      new_qs[index] = key + '=' + value; 
     } 
    } 

    if($("#trade_date_gte").val() != '') { 
     new_qs[new_qs.length] = 'trade_date__gte=' + $("#trade_date_gte").val(); 
    } 
    if($("#trade_date_lte").val() != '') { 
     new_qs[new_qs.length] = 'trade_date__lte=' + $("#trade_date_lte").val(); 
    } 

    window.location = '?' + new_qs.join("&"); 
} 
</script> 

<p> 
From: <br /><input type="text" id="trade_date_gte" value="{{ trade_date_gte|default:'' }}" size="10"><br /> 
To: <br /><input type="text" id="trade_date_lte" value="{{ trade_date_lte|default:'' }}" size="10"> 
</p> 

<ul> 
    <li><a href="#" onclick="javascript:applyDateFilters();">Apply date filters</a></li> 
</ul> 

    {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %} 
    </div> 
{% endif %} 
{% endblock %} 

Kolumna data jest filtrowany jest „trade_date”.

+0

teraz również użyłem twojego filtra (trochę spersonalizowanego) - nadal nie ma tam niczego pod względem django-admin-filtrate. Nadal brakuje 1.4 wsparcia – kosta5

32

W django 1.4 można użyć użytkownika list_filter. spróbuj:

from django.contrib.admin import DateFieldListFilter 
class PersonAdmin(ModelAdmin): 
    list_filter = (
     ('date_field_name', DateFieldListFilter), 
    ) 

To daje pewne wbudowane zakresów, ale to będzie działać, jeśli umieścić zakres dat w url, takich jak:

?date__gte=2009-5-1&date__lt=2009-8-1 

Jeśli potrzebujesz wyboru daty (jak jQuery) , niż musisz przedłużyć DateFieldListFilter. Wysłałem łatkę do django-admin-filtrate, więc sprawdź wkrótce.

+1

czy będzie działać z adminem django grappeli? – andi

+0

@i powinno działać. – maciek

5

Teraz można łatwo wdrożyć niestandardowe filtry administracyjne przy użyciu standardowych interfejsów API Django. Dzień docs że w list_filter można teraz dodać:

klasa dziedziczy z django.contrib.admin.SimpleListFilter, który trzeba podać tytuł i nazwa_parametru przypisuje i zastępują wyszukiwań i metod queryset

I przechodzą do demo (przejdź do drugiego punktu). Używałem tego samodzielnie do dodawania filtrów, których podstawową relacją do obiektów nie są atrybuty modelu, ale wyniki metod na nich, coś, czego nie oferują tradycyjne filtry.

+1

dlaczego głosowanie w dół? – nemesisfixx

+0

Rzeczywiście, bardzo pomocne, tx – ptim

Powiązane problemy