使用SimpleListFilter从自定义属性过滤范围日期



到目前为止,我一直使用Django -daterange_filter在Django Admin中过滤一个范围的日期。只要日期是模型中的一个字段,就可以很好地工作。

然而,现在我的date是模型内的属性,所以我使用SimpleListFilter。

我现在就是这么做的,而且效果很好:

class CalibrationFilter(admin.SimpleListFilter):
    title = ('Last calibration')
    parameter_name = 'calibrationdate'
    def lookups(self,request,mode):
        return (
            ('this_week','This week'),
            ('1_week','Last week'),
            ('2_week','2 weeks ago'),
            ('3_week','3 weeks ago'),
            )
    def queryset(self,request,queryset):
        if self.value() == None:
            return queryset
        if self.value() == 'this_week':
            day = date.today()
            startdate = week_range(day)[0]
            enddate = week_range(day)[1]
            shelves = Shelf.objects.raw(""" [..] here is MySQL query with LEFT JOIN [..] 
                                         WHERE table.date 
                                         BETWEEN '%s' and '%s' """ %
                                         (startdate.strftime('%Y-%m-%d'),
                                          enddate.strftime('%Y-%m-%d'))
                                        )
            return queryset.filter(id__in=[a.id for a in shelves])
        else:
            weeks = '%s' % (self.value())
            num_of_weeks , weeks = weeks.split('_',1)
            day = date.today() - datetime.timedelta(days=int(num_of_weeks)*7)
            startdate = week_range(day)[0]
            enddate = week_range(day)[1]
            shelves = Shelf.objects.raw(""" [..] here is MySQL query with LEFT JOIN [..] 
                                         WHERE table.date 
                                         BETWEEN '%s' and '%s' """ %
                                         (startdate.strftime('%Y-%m-%d'),
                                          enddate.strftime('%Y-%m-%d'))
                                        )
            return queryset.filter(id__in=[a.id for a in shelves])

week_range()是一个函数,用于确定我从这里得到的一周的结束和开始。

我想在过滤器中有两个盒子,From dateTo date, DatePicker,非常类似于django-daterange_filter的实现。

我知道我可以添加一个template到过滤器,但如何修改lookups,以允许两个变量在同一时间?

我终于找到了一条路。我必须从daterange_filter模块编辑filter.py,并创建第二个模板,我称之为filter2.html

#admin.py
from daterange_filter2.filter import DateRangeFilter, DateBookFilter
class LibraryAdmin(admin.ModelAdmin):
list_filter = ('name', ('date', DateRangeFilter), ('shelf__book__date', DateBookFilter),)
admin.site.register(Library, LibraryAdmin)

然后在filter.py中添加以下内容:

#daterange_filter/filter.py
class DateBookFilter(admin.filters.FieldListFilter):
    template = 'daterange_filter/filter2.html'
    def __init__(self, field, request, params, model, model_admin, field_path):
        self.parameter_name = field.name
        self.lookup_kwarg_since = '%s__gte' % self.parameter_name
        self.lookup_kwarg_upto = '%s__lte' % self.parameter_name
        super(DateBookFilter, self).__init__(
            field, request, params, model, model_admin, self.parameter_name)
        self.form = self.get_form(request)
    def choices(self, cl):
        return []
    def expected_parameters(self):
        return [self.lookup_kwarg_since, self.lookup_kwarg_upto]
    def get_form(self, request):
        print self.used_parameters
        return DateRangeForm(data=self.used_parameters,
                             field_name=self.parameter_name)
    def queryset(self, request, queryset):
        if self.form.is_valid():
            # get no null params
            filter_params = dict(filter(lambda x: bool(x[1]),
                                        self.form.cleaned_data.items()))
            from_date = self.form.cleaned_data['%s__gte' % self.parameter_name]
            to_date = self.form.cleaned_data['%s__lte' % self.parameter_name]
            #If none are selected, we return the queryset without filtering
            if from_date is None and to_date is None: 
                return queryset
            #if "From" is empty we will look for records before "To"
            if from_date is None:
                return queryset.filter(shelf__book__date__lt=to_date).order_by('-shelf__book__date')
            #if "To" is empty we will look for records after "From"
            if to_date is None:
                return queryset.filter(shelf__book__date__gt=from_date).order_by('-shelf__book__date')
            #if none of the above then both fields are set so we look between "From" and "To"
            else:
                return queryset.filter(shelf__book__date__range=(from_date,to_date)).order_by('-shelf__book__date')
        else:
            return queryset

admin.filters.FieldListFilter.register(
   lambda f: isinstance(f, models.DateField), DateCalibrationFilter)

最后创建新的模板,我从模板中删除了{{ spec.form.media }},因为它生成了重复的"Today"one_answers"Calendar Picker",格式为:

#templates/daterange_filter/filter2.html
{% load i18n admin_static %}
<h3>{% blocktrans with filter_title=title %} By {{ filter_title }} {% endblocktrans %}</h3>
<link rel="stylesheet" type="text/css" href="{% static "admin/css/widgets.css" %}" />
<style>
    .calendarbox, .clockbox {
        /* Make sure the calendar widget popover displays in front of the sidebar */
        z-index: 1100;
        margin-left: -251px;
    }
    .datetimeshortcuts a{
        /* Make text for "Today" a bit smaller so it appears on one line. */
        font-size: 8pt;
    }
</style>
<form method="GET" action="">
    {{ spec.form.as_p }}
    <p>
    <input type="submit" value="{% trans "Search" %}">
    <input type="reset" value="{% trans "Clear" %}">
    </p>
</form>

希望对大家有所帮助。

最新更新