filters.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. from __future__ import unicode_literals
  2. import datetime
  3. from collections import OrderedDict
  4. try:
  5. import pytz
  6. except ImportError:
  7. pytz = None
  8. from django import forms
  9. from django.conf import settings
  10. from django.contrib import admin
  11. from django.contrib.admin.widgets import AdminDateWidget
  12. from django.template.defaultfilters import slugify
  13. from django.utils.translation import ugettext as _
  14. from django.utils.encoding import smart_text
  15. from django.utils.html import format_html
  16. from django.core.urlresolvers import reverse
  17. try:
  18. from django.contrib.admin.utils import get_model_from_relation
  19. except ImportError: # Django 1.6
  20. from django.contrib.admin.util import get_model_from_relation
  21. try:
  22. from django.forms.utils import flatatt
  23. except ImportError: # Django 1.6
  24. from django.forms.util import flatatt
  25. def make_dt_aware(dt):
  26. if pytz is not None and settings.USE_TZ:
  27. timezone = pytz.timezone(settings.TIME_ZONE)
  28. if dt.tzinfo is not None:
  29. dt = timezone.normalize(dt)
  30. else:
  31. dt = timezone.localize(dt)
  32. return dt
  33. class RelatedFieldAjaxListFilter(admin.RelatedFieldListFilter):
  34. ajax_attrs = None
  35. def has_output(self):
  36. return True
  37. def field_choices(self, field, request, model_admin):
  38. model = field.remote_field.model if hasattr(field, 'remote_field') else field.related_field.model
  39. app_label = model._meta.app_label
  40. model_name = model._meta.object_name
  41. self.ajax_attrs = format_html('{0}', flatatt({
  42. 'data-app-label': app_label,
  43. 'data-model': model_name,
  44. 'data-ajax--url': reverse('jet:model_lookup'),
  45. 'data-queryset--lookup': self.lookup_kwarg
  46. }))
  47. if self.lookup_val is None:
  48. return []
  49. other_model = get_model_from_relation(field)
  50. if hasattr(field, 'rel'):
  51. rel_name = field.rel.get_related_field().name
  52. else:
  53. rel_name = other_model._meta.pk.name
  54. queryset = model._default_manager.filter(**{rel_name: self.lookup_val}).all()
  55. return [(x._get_pk_val(), smart_text(x)) for x in queryset]
  56. class DateRangeFilter(admin.filters.FieldListFilter):
  57. def __init__(self, field, request, params, model, model_admin, field_path):
  58. self.lookup_kwarg_gte = '{}__gte'.format(field_path)
  59. self.lookup_kwarg_lte = '{}__lte'.format(field_path)
  60. super(DateRangeFilter, self).__init__(
  61. field, request, params, model, model_admin, field_path)
  62. self.form = self.get_form(request)
  63. def choices(self, cl):
  64. yield {
  65. 'system_name': slugify(self.title),
  66. 'query_string': cl.get_query_string(
  67. {}, remove=[self.lookup_kwarg_gte, self.lookup_kwarg_lte]
  68. )
  69. }
  70. def expected_parameters(self):
  71. return [self.lookup_kwarg_gte, self.lookup_kwarg_lte]
  72. def queryset(self, request, queryset):
  73. if self.form.is_valid():
  74. validated_data = dict(self.form.cleaned_data.items())
  75. if validated_data:
  76. return queryset.filter(
  77. **self._make_query_filter(validated_data)
  78. )
  79. return queryset
  80. def _make_query_filter(self, validated_data):
  81. query_params = {}
  82. date_value_gte = validated_data.get(self.lookup_kwarg_gte, None)
  83. date_value_lte = validated_data.get(self.lookup_kwarg_lte, None)
  84. if date_value_gte:
  85. query_params['{0}__gte'.format(self.field_path)] = make_dt_aware(
  86. datetime.datetime.combine(date_value_gte, datetime.time.min)
  87. )
  88. if date_value_lte:
  89. query_params['{0}__lte'.format(self.field_path)] = make_dt_aware(
  90. datetime.datetime.combine(date_value_lte, datetime.time.max)
  91. )
  92. return query_params
  93. def get_template(self):
  94. return 'rangefilter/date_filter.html'
  95. template = property(get_template)
  96. def get_form(self, request):
  97. form_class = self._get_form_class()
  98. return form_class(self.used_parameters)
  99. def _get_form_class(self):
  100. fields = self._get_form_fields()
  101. form_class = type(
  102. str('DateRangeForm'),
  103. (forms.BaseForm,),
  104. {'base_fields': fields}
  105. )
  106. form_class.media = self._get_media()
  107. return form_class
  108. def _get_form_fields(self):
  109. return OrderedDict((
  110. (self.lookup_kwarg_gte, forms.DateField(
  111. label='',
  112. widget=AdminDateWidget(attrs={'placeholder': _('From date')}),
  113. localize=True,
  114. required=False
  115. )),
  116. (self.lookup_kwarg_lte, forms.DateField(
  117. label='',
  118. widget=AdminDateWidget(attrs={'placeholder': _('To date')}),
  119. localize=True,
  120. required=False
  121. )),
  122. ))
  123. @staticmethod
  124. def _get_media():
  125. css = [
  126. 'style.css',
  127. ]
  128. return forms.Media(
  129. css={'all': ['range_filter/css/%s' % path for path in css]}
  130. )