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

时间:2014-07-30 06:37:35

标签: python django date filter django-admin

到目前为止,我一直在使用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()是一个函数,用于确定我从here获得的一周结束时间。

我希望过滤器中有2个框From dateTo dateDatePicker,与django-daterange_filter的实现非常相似。

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

1 个答案:

答案 0 :(得分:0)

我终于找到了办法。我必须从filter.py模块中修改daterange_filter,然后创建第二个名为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 }},因为它生成了重复的"今天"和"日历选择器"形式如下:

#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>

希望这对某人有用。