class PostFilter(FilterSet): text = filters.CharFilter(field_name="text", lookup_expr="icontains") is_current = filters.BooleanFilter(method='filter_is_current') class Meta: model = Post fields = ['author', 'text', 'pub_date'] def filter_is_current(self, queryset, name, value): set1 = queryset.filter(pub_date__year=2021) set2 = queryset.filter(pub_date__month=5) return set1 & set2
class TaskFilter(BaseFilterSet): state = filters.CharFilter() worker = HyperlinkRelatedFilter() name = filters.CharFilter() started_at = IsoDateTimeFilter(field_name='started_at') finished_at = IsoDateTimeFilter(field_name='finished_at') parent = HyperlinkRelatedFilter() reserved_resources_record = ReservedResourcesFilter() created_resources = CreatedResourcesFilter() class Meta: model = Task fields = { 'state': ['exact', 'in'], 'worker': ['exact', 'in'], 'name': ['contains'], 'started_at': DATETIME_FILTER_OPTIONS, 'finished_at': DATETIME_FILTER_OPTIONS, 'parent': ['exact'], 'reserved_resources_record': ['exact'], 'created_resources': ['exact'] }
class KadastraalObjectFilter(FilterSet): """ Filter also capable of dealing with landelijk_ids """ verblijfsobject = filters.CharFilter(method="vbo_filter") verblijfsobjecten__id = filters.CharFilter(method="vbo_filter") verblijfsobjecten__landelijk_id = filters.CharFilter(method="vbo_filter") class Meta(object): model = models.KadastraalObject fields = ('verblijfsobject', 'verblijfsobjecten__id', 'verblijfsobjecten__landelijk_id', 'beperkingen__id', 'a_percelen__id', 'g_percelen__id') def vbo_filter(self, queryset, _filter_name, value): if len(value) == 16: return queryset.filter(verblijfsobjecten__landelijk_id=value) return queryset.filter(verblijfsobjecten__id=value)
class MovieFilter(FilterSet): # movies/?title=value title = filters.CharFilter(method='movie_title_filter') class Meta: model = Movie fields = ['title'] def movie_title_filter(self, queryset, title, value): title = self.request.query_params.get(title, None) if title is not None: queryset = queryset.filter(title__icontains=value) return queryset
class DecisionFilter(FilterSet): lease = filters.NumberFilter() reference_number = filters.CharFilter(lookup_expr="contains") class Meta: model = Decision fields = [ "lease", "reference_number", "decision_maker", "decision_date", "type", ]
class BouwDossierFilter(FilterSet): nummeraanduiding = filters.CharFilter(field_name='adressen__nummeraanduidingen', method='array_contains_filter') pand = filters.CharFilter(field_name='adressen__panden', method='array_contains_filter') verblijfsobject = filters.CharFilter(field_name='adressen__verblijfsobjecten', method='array_contains_filter') openbareruimte = filters.CharFilter(field_name='adressen__openbareruimte_id') min_datering = filters.CharFilter(field_name='datering__year', lookup_expr='gte') max_datering = filters.CharFilter(field_name='datering__year', lookup_expr='lte') subdossier = filters.CharFilter(field_name='documenten__subdossier_titel', lookup_expr='istartswith') dossiernr = filters.NumberFilter() dossier = filters.CharFilter(method='dossier_with_stadsdeel') stadsdeel = filters.CharFilter() dossier_type = filters.CharFilter() class Meta: model = models.BouwDossier fields = ( 'dossiernr', 'stadsdeel', 'nummeraanduiding', 'verblijfsobject', 'pand', 'openbareruimte', 'min_datering', 'max_datering', 'subdossier', 'olo_liaan_nummer', ) def dossier_with_stadsdeel(self, queryset, _filter_name, value): stadsdeel, dossiernr = tools.separate_dossier(value) return queryset.filter(stadsdeel=stadsdeel, dossiernr=dossiernr) def array_contains_filter(self, queryset, _filter_name, value): if not isinstance(value, list): value = [value] lookup = '%s__%s' % (_filter_name, 'contains') return queryset.filter(**{lookup: value}).distinct()
class LocationFilter(FilterSet): """ """ id = filters.CharFilter() in_bbox = filters.CharFilter(method='in_bbox_filter', label='bbox') location = filters.CharFilter(method="locatie_filter", label='x,y,r') stadsdeel = filters.ChoiceFilter(choices=STADSDELEN) buurt_code = filters.ChoiceFilter(choices=buurt_choices) class Meta(object): model = Location fields = ( "id", "_signal__id", "buurt_code", "signal__location__stadsdeel", "signal__location__buurt_code", "created_at", "in_bbox", "location", ) def locatie_filter(self, qs, name, value): lon, lat, radius = parse_xyr(value) point = Point(lon, lat) return qs.filter(geometrie__dwithin=(point, bbox.dist_to_deg(radius, lat))) def in_bbox_filter(self, qs, name, value): bbox_values, err = bbox.valid_bbox(value) lon1, lat1, lon2, lat2 = bbox_values poly_bbox = Polygon.from_bbox((lon1, lat1, lon2, lat2)) if err: raise ValidationError(f"bbox invalid {err}:{bbox_values}") return qs.filter(geometrie__bboverlaps=poly_bbox)
class DateFilter(FilterSet): vanaf = filters.CharFilter(label='vanaf', method='vanaf_filter') tot = filters.CharFilter(label='tot', method='tot_filter') op = filters.CharFilter(label='op', method='op_filter') class Meta: model = models.Drukteindex fields = ['timestamp', 'vanaf', 'tot', 'op', 'vollcode'] def vanaf_filter(self, queryset, _name, value): date = convert_to_date(value) if not date: raise ValidationError( 'Please insert a datetime Year-Month-Day-Hour-Minute-Second, like: 26-10-2017-16-00-00' ) queryset = queryset.filter(timestamp__gte=date) return queryset def tot_filter(self, queryset, _name, value): date = convert_to_date(value) if not date: raise ValidationError( 'Please insert a datetime Year-Month-Day-Hour-Minute-Second, like: 26-10-2017-16-00-00' ) queryset = queryset.filter(timestamp__lte=date) return queryset def op_filter(self, queryset, _name, value): date = convert_to_date(value) if not date: raise ValidationError( 'Please insert a datetime Year-Month-Day-Hour-Minute-Second, like: 26-10-2017-16-00-00' ) queryset = queryset.filter(timestamp=date) return queryset
class ReviewFilter(FilterSet): # reviews/?comment=value comment = filters.CharFilter(method='comments_filter') class Meta: model = Review fields = ['comment'] # 'value'가 들어간 comment 필터링 def comments_filter(self, queryset, comment, value): comment = self.request.query_params.get(comment, None) if comment is not None: queryset = queryset.filter(comment__icontains=value) return queryset
class JurisdictionFilter(FilterSet): whitelisted = filters.BooleanFilter() slug = filters.ChoiceFilter(choices=jur_choices, label='Name') name_long = filters.CharFilter(label='Long Name') class Meta: model = models.Jurisdiction fields = [ 'id', 'name', 'name_long', 'whitelisted', 'slug', ]
class SubjectFilter(FilterSet): """ Filter subjecten. """ buurt = filters.CharFilter(method="buurt_filter", label='buurt') zakelijk_recht = filters.NumberFilter(method="recht_filter", label='recht') bewoners = filters.BooleanFilter(method="bewoners_filter") class Meta(object): model = models.KadastraalSubject fields = ( 'naam', 'type', 'buurt', 'kvknummer', 'statutaire_naam', 'zakelijk_recht', ) def buurt_filter(self, queryset, _filter_name, value): """ Buurt code 4 chars """ recht_type = 2 # eigenaar if 'zakelijk_recht' in self.request.GET: recht_type = self.request.GET['zakelijk_recht'] if len(value) != 4: raise drf_serializers.ValidationError('Buurt vollcode is 4 chars') # remove ordering. # SUPER SLOW because of some weirdness. qs = queryset.order_by() return qs.filter(rechten__verblijfsobjecten__buurt__vollcode=value, rechten__aard_zakelijk_recht__code=recht_type) def recht_filter(self, queryset, _filter_name, value): if self.request.GET['buurt']: # will be recht filter will be done # in buurt filter return queryset return queryset.filter(rechten__aard_zakelijk_recht__code=value)
class SidconFilter(FilterSet): """Filtering on sidcon fill level entries.""" container_id = filters.CharFilter(method='container_filter', label='container id') site_id = filters.CharFilter(method='site_filter', label='short site id') days_back = filters.NumberFilter(method='delta_day_filter', label='days back') class Meta(object): model = SidconFillLevel fields = { "scraped_at": FILTERS, "filling": FILTERS, "communication_date_time": FILTERS, "container_id": ['exact'], "days_back": ['exact'], "valid": ['exact'], "short_id": ['exact'], "site_id": ['exact'], } def container_filter(self, qs, name, value): return qs.filter(description=value) def site_filter(self, qs, name, value): return qs.filter(site_id=value) def delta_day_filter(self, qs, name, value): today = datetime.datetime.now() delta = datetime.timedelta(days=int(value)) filter_day = today - delta return qs.filter(communication_date_time__gt=filter_day)
class DistributionFilter(BaseFilterSet): # e.g. # /?name=foo # /?name__in=foo,bar # /?base_path__contains=foo # /?base_path__icontains=foo name = filters.CharFilter() base_path = filters.CharFilter() pulp_label_select = LabelSelectFilter() def __init__(self, *args, **kwargs): """Initialize a DistributionFilter and emit deprecation warnings""" deprecation_logger.warn( _("DistributionFilter is deprecated and could be removed as early as " "pulpcore==3.13; use pulpcore.plugin.serializers.NewDistributionFilter instead." )) return super().__init__(*args, **kwargs) class Meta: model = BaseDistribution fields = { "name": NAME_FILTER_OPTIONS, "base_path": ["exact", "contains", "icontains", "in"], }
class Pulp2RepositoriesFilter(BaseFilterSet): """ Filter for Pulp2Repositories ViewSet. """ pulp2_repo_id = filters.CharFilter() is_migrated = filters.BooleanFilter() not_in_plan = filters.BooleanFilter() class Meta: model = Pulp2Repository fields = { 'pulp2_repo_id': ['exact', 'in'], 'is_migrated': ['exact'], 'not_in_plan': ['exact'] }
def filter_factory(ds_name, model): model_name = ds_name.upper() + 'GenericFilter' ds = DataSet.objects.get(name=ds_name) name_field = ds.name_field or 'UNKNOWN' geometry_field = ds.geometry_field or 'UNKNOWN' geometry_type = ds.geometry_type or 'UNKNOWN' fields = [name_field, geometry_field] location_filter_name = ':'.join([geometry_field, geometry_type]) location = filters.CharFilter(field_name=location_filter_name, method="location_filter") name = filters.CharFilter(field_name=name_field, method="name_filter") new_meta_attrs = { 'model': model, 'fields': fields, } new_meta = type('Meta', (object, ), new_meta_attrs) new_attrs = { '__module__': 'various_small_datasets.gen_api.filters', 'Meta': new_meta, geometry_field: location, name_field: name, } return type(model_name, (GenericFilter, ), new_attrs)
class UserFilter(FilterSet): nickname = filters.CharFilter(field_name='nickname', lookup_expr="icontains") is_hy1 = filters.BooleanFilter(method='filter_is_hy1') class Meta: model = User fields = ['nickname'] def filter_is_hy1(self, queryset, name, value): filtered_queryset = queryset.filter(nickname__contains="1") filtered_queryset2 = queryset.filter(~Q(nickname__contains="1")) if value == True: return filtered_queryset else: return filtered_queryset2
class Pulp2RepositoriesFilter(BaseFilterSet): """ Filter for Pulp2Repositories ViewSet. """ pulp2_repo_id = filters.CharFilter() is_migrated = filters.BooleanFilter() not_in_plan = filters.BooleanFilter() class Meta: model = Pulp2Repository fields = { "pulp2_repo_id": ["exact", "in"], "is_migrated": ["exact"], "not_in_plan": ["exact"], }
class RemoteFilter(BaseFilterSet): """ Plugin remote filter should: - inherit from this class - add any specific filters if needed - define a `Meta` class which should: - specify a plugin remote model for which filter is defined - extend `fields` with specific ones """ name = filters.CharFilter() pulp_last_updated = IsoDateTimeFilter() class Meta: model = Remote fields = {"name": NAME_FILTER_OPTIONS, "pulp_last_updated": DATETIME_FILTER_OPTIONS}
class FileSystemExporterFilter(BaseFilterSet): """ Plugin file system exporter filter should: - inherit from this class - add any specific filters if needed - define a `Meta` class which should: - specify a plugin remote model for which filter is defined - extend `fields` with specific ones """ name = filters.CharFilter() class Meta: model = FileSystemExporter fields = { 'name': NAME_FILTER_OPTIONS, }
class ParkeervakFilter(FilterSet): id = filters.CharFilter() class Meta(object): model = Parkeervak fields = ( 'id', 'buurtcode', 'stadsdeel', 'straatnaam', 'soort', 'aantal', 'type', 'e_type', 'bord', )
class TaskFilter(filterset.FilterSet): state = filters.CharFilter() worker = HyperlinkRelatedFilter() started_at = filters.IsoDateTimeFilter(name='started_at') finished_at = filters.IsoDateTimeFilter(name='finished_at') parent = HyperlinkRelatedFilter() class Meta: model = Task fields = { 'state': ['exact', 'in'], 'worker': ['exact', 'in'], 'started_at': DATETIME_FILTER_OPTIONS, 'finished_at': DATETIME_FILTER_OPTIONS, 'parent': ['exact'] }
class GenericFilter(FilterSet): format = filters.CharFilter(method="format_filter") class Meta(object): model = None fields = () @staticmethod def location_filter(queryset, _filter_name, value): """ Filter based on the geolocation. This filter actually expect 2 or 3 numerical values: x, y and optional radius The value given is broken up by ',' and converted to the value tuple """ point, radius, err = validate_x_y(value) if err: log.exception(err) raise rest_serializers.ValidationError(err) # Creating one big queryset (geo_field, geo_type) = _filter_name.split(':') if geo_type.lower() == 'polygon' and radius is None: args = {'__'.join([geo_field, 'contains']): point} biz_results = queryset.filter(**args) elif radius is not None: args = {'__'.join([geo_field, 'dwithin']): (point, D(m=radius))} biz_results = queryset.filter(**args).annotate( afstand=Distance(geo_field, point)) else: err = "Radius in argument expected" log.exception(err) raise rest_serializers.ValidationError(err) return biz_results @staticmethod def name_filter(queryset, _filter_name, value): args = {'__'.join([_filter_name, 'icontains']): value} return queryset.filter(**args) @staticmethod def format_filter(queryset, _filter_name, value): return queryset
class ExporterFilter(BaseFilterSet): """ Plugin exporter filter should: - inherit from this class - add any specific filters if needed - define a `Meta` class which should: - specify a plugin exporter model for which filter is defined - extend `fields` with specific ones """ name = filters.CharFilter() last_export = IsoDateTimeFilter() class Meta: model = Exporter fields = { 'name': NAME_FILTER_OPTIONS, 'last_export': DATETIME_FILTER_OPTIONS }
class UserFilterSet(FilterSet): id = filters.NumberFilter() username = filters.CharFilter(lookup_expr='icontains') active = filters.BooleanFilter(field_name='is_active') role = filters.ModelMultipleChoiceFilter(queryset=_get_group_queryset(), to_field_name='name', field_name='groups__name') order = OrderingExtraKwargsFilter( fields=( ('username', 'username'), ('is_active', 'active'), ), extra_kwargs={ 'username': {'apply': Lower} # Will apply the Lower function when ordering } )
class MetingenFilter(FilterSet): """ Filter metingen op bbox """ bbox = filters.CharFilter(method="bbox_filter") class Meta(object): model = models.Scan fields = ( 'bbox', 'scan_moment', 'device_id', 'scan_source', 'nha_hoogte', 'nha_nr', 'qualcode', 'buurtcode', 'sperscode', 'parkeervak_id', 'parkeervak_soort', 'bgt_wegdeel', 'bgt_wegdeel_functie', ) def box_filter(self, queryset, _filter_name, value): bbox_values, err = bbox.valid_bbox(value) if err: return queryset lat1, lon1, lat2, lon2 = bbox_values poly_bbox = Polygon.from_bbox((lon1, lat1, lon2, lat2)) return queryset.filter( Q(**{"geometrie__bboverlaps": poly_bbox}))
class SpaceFilter(rest_framework.FilterSet): contains_more_than_n_categories = rest_framework.CharFilter( label=('Содержится видов животных больше чем n:'), method="filter_by_categories_count") categories__animals__name = filters.CharFilter( label=('Фильтр по имени животного:')) categories__animals__description = filters.CharFilter( label=('Фильтр по описанию животного:')) categories__animals__gender = filters.CharFilter( label=('Фильтр по полу животного:')) categories__animals__age = filters.CharFilter( label=('Фильтр по возрасту животного:')) categories__animals__created_at = filters.CharFilter( label=('Фильтр по дате появления животного:')) categories__animals__color = filters.CharFilter( label=('Фильтр по цвету животного:')) class Meta: model = Space fields = [ "name", "placementperiods", "description", "illumination", "type", "square", "categories__animals__name", "categories__animals__description", "categories__animals__gender", "categories__animals__age", "categories__animals__created_at", "categories__animals__color", ] def filter_by_categories_count(self, queryset, name, value): queryset = Space.objects.annotate( num_categories=Count('categories')).filter( num_categories__gt=value) return queryset
class AnimalFilter(rest_framework.FilterSet): category__space__name = filters.CharFilter( label=('Фильтр по имени вольера:')) category__space__created_at = filters.CharFilter( label=('Фильтр по дате создания вольера:')) category__space__description = filters.CharFilter( label=('Фильтр по описанию вольера:')) category__space__type = filters.CharFilter( label=('Фильтр по типу вольера:')) category__space__square = filters.CharFilter( label=('Фильтр по площади вольера:')) category__space__illumination = filters.CharFilter( label=('Фильтр по типу освещения в вольере:')) class Meta: model = Animal fields = [ "category__space__name", "category__space__created_at", "category__space__description", "category__space__type", "category__space__square", "category__space__illumination", ]
class OrderOptionFilter(FilterSet): customer_code = filters.CharFilter(help_text='客户代码')
class FreightTMOrdFilterSet(FilterSet): channel_code = filters.CharFilter(help_text='客户代码') freight = filters.NumberFilter(help_text='运单')
class SignalFilterSet(FilterSet): id = filters.NumberFilter() address_text = filters.CharFilter(field_name='location__address_text', lookup_expr='icontains') area_code = filters.ChoiceFilter(field_name='location__area_code', choices=area_choices) area_type_code = filters.ChoiceFilter(field_name='location__area_type_code', choices=area_type_choices) buurt_code = filters.MultipleChoiceFilter(field_name='location__buurt_code', choices=buurt_choices) category_id = filters.MultipleChoiceFilter(field_name='category_assignment__category_id', choices=category_choices) category_slug = filters.ModelMultipleChoiceFilter( queryset=_get_child_category_queryset(), to_field_name='slug', field_name='category_assignment__category__slug', ) contact_details = filters.MultipleChoiceFilter(method='contact_details_filter', choices=contact_details_choices) created_before = filters.IsoDateTimeFilter(field_name='created_at', lookup_expr='lte') directing_department = filters.MultipleChoiceFilter( method='directing_department_filter', choices=department_choices ) created_after = filters.IsoDateTimeFilter(field_name='created_at', lookup_expr='gte') feedback = filters.ChoiceFilter(method='feedback_filter', choices=feedback_choices) has_changed_children = filters.MultipleChoiceFilter(method='has_changed_children_filter', choices=boolean_choices) kind = filters.MultipleChoiceFilter(method='kind_filter', choices=kind_choices) # SIG-2636 incident_date = filters.DateFilter(field_name='incident_date_start', lookup_expr='date') incident_date_before = filters.DateFilter(field_name='incident_date_start', lookup_expr='date__gte') incident_date_after = filters.DateFilter(field_name='incident_date_start', lookup_expr='date__lte') maincategory_slug = filters.ModelMultipleChoiceFilter( queryset=_get_parent_category_queryset(), to_field_name='slug', field_name='category_assignment__category__parent__slug', ) note_keyword = filters.CharFilter(method='note_keyword_filter') priority = filters.MultipleChoiceFilter(field_name='priority__priority', choices=Priority.PRIORITY_CHOICES) source = filters.MultipleChoiceFilter(choices=source_choices) stadsdeel = filters.MultipleChoiceFilter(field_name='location__stadsdeel', choices=stadsdelen_choices) status = filters.MultipleChoiceFilter(field_name='status__state', choices=status_choices) type = filters.MultipleChoiceFilter(field_name='type_assignment__name', choices=Type.CHOICES) updated_before = filters.IsoDateTimeFilter(field_name='updated_at', lookup_expr='lte') updated_after = filters.IsoDateTimeFilter(field_name='updated_at', lookup_expr='gte') def _cleanup_form_data(self): """ Cleanup the form data """ self.form.cleaned_data.pop('category_slug', None) self.form.cleaned_data.pop('maincategory_slug', None) if not self.form.cleaned_data.get('area_code', None) or not self.form.cleaned_data.get('area_type_code', None): self.form.cleaned_data.pop('area_code', None) self.form.cleaned_data.pop('area_type_code', None) def filter_queryset(self, queryset): """ Add custom category filtering to the filter_queryset """ if not self.form.cleaned_data['category_id']: main_categories = self.form.cleaned_data['maincategory_slug'] sub_categories = self.form.cleaned_data['category_slug'] if main_categories or sub_categories: queryset = queryset.filter( Q(category_assignment__category__parent_id__in=[c.pk for c in main_categories]) | Q(category_assignment__category_id__in=[c.pk for c in sub_categories]) ) self._cleanup_form_data() queryset = super(SignalFilterSet, self).filter_queryset(queryset=queryset) return queryset.distinct() # Custom filter functions def contact_details_filter(self, queryset, name, value): """ Filter `signals.Signal` instances according to presence of contact details. """ choices = value # we have a MultipleChoiceFilter ... # Deal with all choices selected, or none selected: if len(choices) == len(contact_details_choices()): # No filters are present, or ... all filters are present. In that # case we want all Signal instances with an email address, or a # phone number, or none of those (according to) the UX design. # This is the same as not filtering, hence in both cases just # return the queryset. return queryset # Set-up our Q objects for the individual options. has_no_email = (Q(reporter__email__isnull=True) | Q(reporter__email='')) has_no_phone = (Q(reporter__phone__isnull=True) | Q(reporter__phone='')) is_anonymous = has_no_email & has_no_phone q_objects = { 'email': ~has_no_email, 'phone': ~has_no_phone, 'none': is_anonymous, } # The individual choices have to be combined using logical OR: q_total = q_objects[choices.pop()] while choices: q_total |= q_objects[choices.pop()] return queryset.filter(q_total) def directing_department_filter(self, queryset, name, value): """ Filter Signals on directing department. * A directing department can only be set on a Parent Signal * When providing the option "null" select all parent Signals without one or more directing departments * When providing on or more department codes as options select all parent Signals which match directing departments Example 1: "?directing_department=ASC" will select all parent Signals where ASC is the directing department Example 2: "?directing_department=ASC&directing_department=null" will select all parent Signals without a directing department OR ASC as the directing department Example 3: "?directing_department=null" will select all parent Signals without a directing department """ choices = value # we have a MultipleChoiceFilter ... if len(choices) == len(department_choices()): # No filters are present, or ... all filters are present. In that case we want all Signal instances return queryset # Directing departments are only set on parent Signals parent_q_filter = (Q(parent__isnull=True) & Q(children__isnull=False)) if 'null' in choices and len(choices) == 1: # "?directing_department=null" will select all parent Signals without a directing department return queryset.filter( parent_q_filter & ( Q(directing_departments_assignment__isnull=True) | Q(directing_departments_assignment__departments__isnull=True) ) ) elif 'null' in choices and len(choices) > 1: # "?directing_department=ASC&directing_department=null" will select all parent Signals without a directing # department OR ASC as the directing department choices.pop(choices.index('null')) return queryset.filter( parent_q_filter & ( Q(directing_departments_assignment__isnull=True) | Q(directing_departments_assignment__departments__isnull=True) | Q(directing_departments_assignment__departments__code__in=choices) ) ) elif len(choices): # "?directing_department=ASC" will select all parent Signals where ASC is the directing department return queryset.filter( parent_q_filter & Q(directing_departments_assignment__departments__code__in=choices) ) return queryset def feedback_filter(self, queryset, name, value): # Only signals that have feedback queryset = queryset.annotate(feedback_count=Count('feedback')).filter(feedback_count__gte=1) if value in ['satisfied', 'not_satisfied']: is_satisfied = True if value == 'satisfied' else False queryset = queryset.annotate( feedback_max_created_at=Max('feedback__created_at'), feedback_max_submitted_at=Max('feedback__submitted_at') ).filter( feedback__is_satisfied=is_satisfied, feedback__submitted_at__isnull=False, feedback__created_at=F('feedback_max_created_at'), feedback__submitted_at=F('feedback_max_submitted_at') ) elif value == 'not_received': queryset = queryset.annotate( feedback_max_created_at=Max('feedback__created_at') ).filter( feedback__submitted_at__isnull=True, feedback__created_at=F('feedback_max_created_at') ) return queryset def kind_filter(self, queryset, name, value): choices = value # we have a MultipleChoiceFilter ... if (len(choices) == len(kind_choices()) or {'signal', 'parent_signal', 'child_signal'} == set(choices) or {'parent_signal', 'exclude_parent_signal'} == set(choices)): return queryset q_objects = { 'signal': (Q(parent__isnull=True) & Q(children__isnull=True)), 'parent_signal': (Q(parent__isnull=True) & Q(children__isnull=False)), 'exclude_parent_signal': ~(Q(parent__isnull=True) & Q(children__isnull=False)), 'child_signal': (Q(parent__isnull=False)), } q_filter = q_objects[choices.pop()] while choices: q_filter |= q_objects[choices.pop()] return queryset.filter(q_filter) if q_filter else queryset def note_keyword_filter(self, queryset, name, value): return queryset.filter(notes__text__icontains=value) def has_changed_children_filter(self, queryset, name, value): # we have a MultipleChoiceFilter ... choices = list(set(map(lambda x: True if x in [True, 'True', 'true', 1] else False, value))) q_filter = Q(children__isnull=False) if len(choices) == 2: return queryset.filter(q_filter) if True in choices: q_filter &= Q(updated_at__lt=F('children__updated_at')) # noqa Selects all parent signals with changes in the child signals if False in choices: q_filter &= Q(updated_at__gt=F('children__updated_at')) # noqa Selects all parent signals with NO changes in the child signals return queryset.filter(q_filter)