class UsersFilter(FilterSet): """Filter for users""" attributes = CharFilter( field_name="attributes", lookup_expr="", label="Attributes", method="filter_attributes", ) is_superuser = BooleanFilter(field_name="ak_groups", lookup_expr="is_superuser") groups_by_name = ModelMultipleChoiceFilter( field_name="ak_groups__name", to_field_name="name", queryset=Group.objects.all(), ) groups_by_pk = ModelMultipleChoiceFilter( field_name="ak_groups", queryset=Group.objects.all(), ) # pylint: disable=unused-argument def filter_attributes(self, queryset, name, value): """Filter attributes by query args""" try: value = loads(value) except ValueError: raise ValidationError(detail="filter: failed to parse JSON") if not isinstance(value, dict): raise ValidationError( detail="filter: value must be key:value mapping") qs = {} for key, _value in value.items(): qs[f"attributes__{key}"] = _value try: _ = len(queryset.filter(**qs)) return queryset.filter(**qs) except ValueError: return queryset class Meta: model = User fields = [ "username", "email", "name", "is_active", "is_superuser", "attributes", "groups_by_name", "groups_by_pk", ]
def test_callable_queryset(self): request = mock.NonCallableMock(spec=[]) qs = mock.NonCallableMock(spec=[]) qs_callable = mock.Mock(return_value=qs) f = ModelMultipleChoiceFilter(queryset=qs_callable) f.parent = mock.Mock(request=request) field = f.field qs_callable.assert_called_with(request) self.assertEqual(field.queryset, qs)
def test_filtering_to_field_name(self): qs = User.objects.all() f = ModelMultipleChoiceFilter(field_name='first_name', to_field_name='first_name', queryset=qs) user = User.objects.create(first_name='Firstname') self.assertEqual(f.get_filter_predicate(user), {'first_name': 'Firstname'}) self.assertEqual(f.get_filter_predicate('FilterValue'), {'first_name': 'FilterValue'}) self.assertEqual(list(f.filter(qs, ['Firstname'])), [user]) self.assertEqual(list(f.filter(qs, [user])), [user])
class PropertyModelMultipleChoiceFilterSet(PropertyFilterSet): # No Property filter since working directly with Foreign Keys related = ModelMultipleChoiceFilter(queryset=models.ModelChoiceFilterRelatedModel.objects.all()) class Meta: model = models.ModelChoiceFilterModel fields = ['related']
class TaggedRecipeFilterSet(FilterSet): tags = ModelMultipleChoiceFilter( queryset=Tag.objects.all(), field_name='tags__title', to_field_name='title', ) class Meta: model = Recipe fields = ('tags', )
class SiteFilterSet(ZoningFilterSet, StructureRelatedFilterSet): orientation = MultipleChoiceFilter(choices=Site.ORIENTATION_CHOICES, method='filter_super') wind = MultipleChoiceFilter(choices=Site.ORIENTATION_CHOICES, method='filter_super') practice = ModelMultipleChoiceFilter(queryset=Practice.objects.all(), method='filter_super') sector = ModelMultipleChoiceFilter(queryset=Sector.objects.all(), method='filter_sector', label=_("Sector")) class Meta(StructureRelatedFilterSet.Meta): model = Site fields = StructureRelatedFilterSet.Meta.fields + [ 'sector', 'practice', 'labels', 'themes', 'portal', 'source', 'information_desks', 'web_links', 'type', 'orientation', 'wind', ] def filter_super(self, qs, name, values): if not values: return qs return qs.filter(**{ '{}__in'.format(name): values }).get_ancestors(include_self=True) def filter_sector(self, qs, name, values): if not values: return qs return qs.filter(practice__sector__in=values).get_ancestors( include_self=True)
class OutpostFilter(FilterSet): """Filter for Outposts""" providers_by_pk = ModelMultipleChoiceFilter( field_name="providers", queryset=Provider.objects.all(), ) class Meta: model = Outpost fields = { "providers": ["isnull"], "name": ["iexact", "icontains"], "service_connection__name": ["iexact", "icontains"], "managed": ["iexact", "icontains"], }
class InterfaceFilterClass(FilterSet): """Exists only to have a sane implementation of multiple choice filters""" netbox = ModelMultipleChoiceFilter(queryset=manage.Netbox.objects.all()) class Meta(object): model = manage.Interface fields = ( 'ifname', 'ifindex', 'ifoperstatus', 'netbox', 'trunk', 'ifadminstatus', 'iftype', 'baseport', 'module__name', 'vlan', )
def test_filtering_to_field_name(self): qs = User.objects.all() f = ModelMultipleChoiceFilter(name='first_name', to_field_name='first_name', queryset=qs) user = User.objects.create(first_name='Firstname') self.assertEqual(f.get_filter_predicate(user), {'first_name': 'Firstname'}) self.assertEqual(f.get_filter_predicate('FilterValue'), {'first_name': 'FilterValue'}) self.assertEqual(list(f.filter(qs, ['Firstname'])), [user]) self.assertEqual(list(f.filter(qs, [user])), [user])
class ContatoAgrupadoPorProcessoFilterSet(FilterSet): AGRUPADO_POR_NADA = 'sem_agrupamento' AGRUPADO_POR_TITULO = 'titulo' AGRUPADO_POR_IMPORTANCIA = 'importancia' AGRUPADO_POR_TOPICO = 'topicos__descricao' AGRUPADO_POR_ASSUNTO = 'assuntos__descricao' AGRUPADO_POR_STATUS = 'status__descricao' AGRUPADO_POR_CLASSIFICACAO = 'classificacoes__descricao' AGRUPAMENTO_CHOICE = ( (AGRUPADO_POR_NADA, _('Sem Agrupamento')), (AGRUPADO_POR_TITULO, _('Por Título de Processos')), (AGRUPADO_POR_IMPORTANCIA, _('Por Importância')), (AGRUPADO_POR_TOPICO, _('Por Tópicos')), (AGRUPADO_POR_ASSUNTO, _('Por Assuntos')), (AGRUPADO_POR_STATUS, _('Por Status')), (AGRUPADO_POR_CLASSIFICACAO, _('Por Classificação')), ) search = CharFilter(method='filter_search') agrupamento = ChoiceFilter(required=False, empty_label=None, choices=AGRUPAMENTO_CHOICE, method='filter_agrupamento') importancia = MultipleChoiceFilter(required=False, choices=IMPORTANCIA_CHOICE, method='filter_importancia') status = ModelMultipleChoiceFilter(required=False, queryset=StatusProcesso.objects.all(), method='filter_status') def filter_agrupamento(self, queryset, field_name, value): return queryset def filter_importancia(self, queryset, field_name, value): if not value: return queryset q = None for i in value: q = q | Q(importancia=i) if q else Q(importancia=i) return queryset.filter(q) def filter_status(self, queryset, field_name, value): if not value: return queryset q = None for sta in value: q = q | Q(status=sta) if q else Q(status=sta) return queryset.filter(q) def filter_search(self, queryset, field_name, value): query = normalize(value) query = query.split(' ') if query: q = Q() for item in query: if not item: continue q = q & Q(search__icontains=item) if q: queryset = queryset.filter(q) return queryset class Meta: model = Processo fields = [ 'search', 'data', 'topicos', 'importancia', 'classificacoes', 'assuntos', 'status', ] filter_overrides = { models.DateField: { 'filter_class': DataRangeFilter, 'extra': lambda f: { 'label': '%s (%s)' % (f.verbose_name, _('Inicial - Final')), 'widget': RangeWidgetOverride } } } def __init__(self, data=None, queryset=None, prefix=None, **kwargs): workspace = kwargs.pop('workspace') super(ContatoAgrupadoPorProcessoFilterSet, self).__init__(data=data, queryset=queryset, prefix=prefix, **kwargs) c1_row1 = to_row([ ('search', 7), ('data', 5), ('importancia', 4), ('status', 4), ('classificacoes', 4), ('topicos', 6), ('assuntos', 6), ]) col1 = Fieldset( _('Informações para Seleção de Processos'), c1_row1, to_row([ (SubmitFilterPrint('filter', value=_('Filtrar'), css_class='btn-outline-primary pull-right', type='submit'), 12) ])) col2 = Fieldset( _('Inf p/ Impressão'), 'agrupamento', SubmitFilterPrint('print', value=_('Imprimir'), css_class='btn-primary pull-right', type='submit')) rows = to_row([ (col1, 9), (col2, 3), ]) self.form.helper = FormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout(rows, ) self.form.fields['search'].label = _('Filtrar Títulos de Processos') self.form.fields['topicos'].widget = forms.SelectMultiple( attrs={'size': '7'}) self.form.fields['topicos'].queryset = TopicoProcesso.objects.all() self.form.fields['assuntos'].widget = forms.SelectMultiple( attrs={'size': '7'}) self.form.fields['assuntos'].queryset = AssuntoProcesso.objects.filter( workspace=workspace) self.form.fields['importancia'].widget = forms.CheckboxSelectMultiple() #self.form.fields['importancia'].inline_class = True self.form.fields[ 'classificacoes'].widget = forms.CheckboxSelectMultiple() self.form.fields['status'].widget = forms.CheckboxSelectMultiple() """#self.form.fields['status'].inline_class = True self.form.fields['status'].choices = list( self.form.fields['status'].choices) del self.form.fields['status'].choices[0]""" self.form.fields['agrupamento'].label = _('Agrupar Contatos') self.form.fields['agrupamento'].widget = forms.RadioSelect()
class ContatoAgrupadoPorGrupoFilterSet(FilterSet): municipio = ModelChoiceFilter(required=False, label=Municipio._meta.verbose_name, queryset=Municipio.objects.all(), method='filter_municipio') grupo = ModelMultipleChoiceFilter( required=False, label=GrupoDeContatos._meta.verbose_name_plural, queryset=GrupoDeContatos.objects.all(), method='filter_grupo') def filter_municipio(self, queryset, field_name, value): queryset = queryset.filter(endereco_set__municipio=value) return queryset def filter_grupo(self, queryset, field_name, value): queryset = queryset.filter(grupodecontatos_set__in=value) return queryset.order_by('grupodecontatos_set__nome', 'nome') class Meta: model = Contato fields = ('municipio', 'grupo') def __init__(self, data=None, queryset=None, prefix=None, strict=None, **kwargs): workspace = kwargs.pop('workspace') super(ContatoAgrupadoPorGrupoFilterSet, self).__init__(data=data, queryset=queryset, prefix=prefix, strict=strict, **kwargs) c1_row1 = to_row([ ('municipio', 7), ('grupo', 7), ]) col1 = Fieldset( _('Informações para Seleção de Contados'), c1_row1, to_row([ (SubmitFilterPrint('filter', value=_('Filtrar'), css_class='btn-outline-primary pull-right', type='submit'), 12) ])) col2 = Fieldset( _('Inf p/ Impressão'), SubmitFilterPrint('print', value=_('Imprimir'), css_class='btn-primary pull-right', type='submit')) rows = to_row([ (col1, 9), (col2, 3), ]) self.form.helper = FormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout(rows, ) self.form.fields['grupo'].queryset = GrupoDeContatos.objects.filter( workspace=workspace) self.form.fields['municipio'].queryset = Municipio.objects.all()
class CommunityFilter(django_filters.FilterSet): """Filter for Community.""" admin_areas = ModelMultipleChoiceFilter( label="DBCA Regions and Districts", queryset=Area.objects.filter(area_type__in=[ Area.AREATYPE_DBCA_REGION, Area.AREATYPE_DBCA_DISTRICT ]).order_by("area_type", "name"), method='communities_occurring_in_area') eoo = geo_models.PolygonField() aoo = CharFilter( label="Area of Occupancy (AOO) intersects", widget=LeafletWidget(), method="communities_occurring_in_poly", ) conservation_level = MultipleChoiceFilter( label="Conservation Level", choices=cons_models.ConservationCategory.LEVEL_CHOICES, method='community_conservation_level') categories = ModelMultipleChoiceFilter( label="Conservation Listing Categories", queryset=cons_models.ConservationCategory.objects.filter( conservation_list__scope_communities=True).order_by( "conservation_list__code", "rank").prefetch_related("conservation_list"), method="communities_with_conservation_criteria") class Meta: """Class opts.""" model = Community fields = [ "admin_areas", "eoo", "aoo", "conservation_level", "categories", "code", "name", "description", ] filter_overrides = FILTER_OVERRIDES def communities_occurring_in_area(self, queryset, name, value): """Return Communities occurring in the given Area. * The filter returns a list of Area objects as ``value`` * We need to extract their PKs to create a queryset equivalent to the list of objects ``value``. Only querysets allow agggregation, not lists. * A search_area Multipolygon is collected from the geoms of Areas in ``value`` * The Taxon PKs are calculated from occurrences (CommunityAreaEncounters) ``intersect``ing the search_area * The queryset is filtered by the list of Community PKs with occurrences in the matching areas """ if value: area_pks = [area.pk for area in value] search_area = Area.objects.filter(pk__in=area_pks).aggregate( Collect('geom'))["geom__collect"] pks = set([ x["community__pk"] for x in occ_models.CommunityAreaEncounter.objects.filter( Q(point__intersects=search_area) | Q(geom__intersects=search_area)).values("community__pk") ]) return queryset.filter(pk__in=pks) else: return queryset def communities_occurring_in_poly(self, queryset, name, value): """Return Communities occurring in the given Area polygon. * The filter returns a ``value`` * (magic) value becomes search area * The Community PKs are calculated from occurrences (CommunityAreaEncounters) ``intersect``ing the search_area * The queryset is filtered by the list of Community PKs with occurrences """ if value: pks = set([ x["community__pk"] for x in occ_models.CommunityAreaEncounter.objects.filter( Q(point__intersects=value) | Q(geom__intersects=value)).values("community__pk") ]) return queryset.filter(pk__in=pks) else: return queryset def community_conservation_level(self, queryset, name, value): """Return Communities matching a conservation level. * The filter returns a list of ConservationCategory levels as ``value`` * The Community PKs are calculated from active, WA CommunityConservationListings with categories matching the level * The queryset is filtered by the list of Community PKs with active community listings in WA matching the conservation level """ if value: pks = set([ x["community__pk"] for x in cons_models.CommunityConservationListing.objects. filter(scope=cons_models.ConservationListing. SCOPE_WESTERN_AUSTRALIA, status=cons_models.ConservationListing.STATUS_EFFECTIVE, category__level__in=value).values("community__pk") ]) return queryset.filter(pk__in=pks) else: return queryset def communities_with_conservation_criteria(self, queryset, name, value): """Return Communities matching a conservation level. * The filter returns a list of ConservationCategories as ``value`` * The Taxon PKs are calculated from CommunityConservationListings with categories matching the list of categories in ``value`` * The queryset is filtered by the list of Taxon PKs matching the conservation level """ if value: pks = set([ x["community__pk"] for x in cons_models.CommunityConservationListing.objects. filter(category__in=value).values("community__pk") ]) return queryset.filter(pk__in=pks) else: return queryset
class TaxonFilter(django_filters.FilterSet): """Filter for Taxon.""" is_terminal_taxon = BooleanFilter(label="Terminal Taxon", widget=BooleanWidget(), method="filter_leaf_nodes") current = BooleanFilter(label="Taxonomic name is current", widget=BooleanWidget()) admin_areas = ModelMultipleChoiceFilter( label="DBCA Regions and Districts", queryset=Area.objects.filter(area_type__in=[ Area.AREATYPE_DBCA_REGION, Area.AREATYPE_DBCA_DISTRICT ]).order_by("area_type", "name"), method='taxa_occurring_in_area') eoo = geo_models.PolygonField() aoo = CharFilter( label="Area of Occupancy (AOO) intersects", widget=LeafletWidget(), method="taxa_occurring_in_poly", ) conservation_level = MultipleChoiceFilter( label="Conservation Level", choices=cons_models.ConservationCategory.LEVEL_CHOICES, method='taxon_conservation_level') categories = ModelMultipleChoiceFilter( label="Conservation Listing Categories", queryset=cons_models.ConservationCategory.objects.filter( conservation_list__scope_species=True).order_by( "conservation_list__code", "rank").prefetch_related("conservation_list"), method="taxa_with_conservation_criteria") class Meta: """Class opts.""" model = Taxon fields = [ "paraphyletic_groups", "admin_areas", "eoo", "aoo", "conservation_level", "categories", "taxonomic_name", "vernacular_names", "rank", "is_terminal_taxon", "current", "publication_status", "name_id", "field_code" ] filter_overrides = FILTER_OVERRIDES def filter_leaf_nodes(self, queryset, name, value): """Return terminal taxa (leaf nodes) if value is true.""" return queryset.filter(children__isnull=value) def taxa_occurring_in_area(self, queryset, name, value): """Return Taxa occurring in the given list of ``Area`` instances. * The filter returns a list of Area objects as ``value`` * We need to extract their PKs to create a queryset equivalent to the list of objects ``value``. Only querysets allow agggregation, not lists. * A search_area Multipolygon is collected from the geoms of Areas in ``value`` * The Taxon PKs are calculated from occurrences (TaxonAreaEncounters) ``intersect``ing the search_area * The queryset is filtered by the list of Taxon PKs with occurrences """ if value: area_pks = [area.pk for area in value] search_area = Area.objects.filter(pk__in=area_pks).aggregate( Collect('geom'))["geom__collect"] taxon_pks_in_area = set([ x["taxon__pk"] for x in occ_models.TaxonAreaEncounter.objects.filter( Q(point__intersects=search_area) | Q(geom__intersects=search_area)).values("taxon__pk") ]) return queryset.filter(pk__in=taxon_pks_in_area) else: return queryset def taxa_occurring_in_poly(self, queryset, name, value): """Return Taxa occurring in the given Area polygon. * The filter returns a ``value`` * (magic) value becomes search area * The Taxon PKs are calculated from occurrences (TaxonAreaEncounters) ``intersect``ing the search_area * The queryset is filtered by the list of Taxon PKs with occurrences """ if value: taxon_pks_in_area = set([ x["taxon__pk"] for x in occ_models.TaxonAreaEncounter.objects.filter( Q(point__intersects=value) | Q(geom__intersects=value)).values("taxon__pk") ]) return queryset.filter(pk__in=taxon_pks_in_area) else: return queryset def taxon_conservation_level(self, queryset, name, value): """Return Taxa matching a conservation level. * The filter returns a list of ConservationCategory levels as ``value`` * The Taxon PKs are calculated from active, WA CommunityConservationListings with categories matching the level * The queryset is filtered by the list of Taxon PKs with active taxon listings in WA matching the conservation level """ if value: taxon_pks = set([ x["taxon__pk"] for x in cons_models.TaxonConservationListing.objects.filter( scope=cons_models.ConservationListing. SCOPE_WESTERN_AUSTRALIA, status=cons_models.ConservationListing.STATUS_EFFECTIVE, category__level__in=value).values("taxon__pk") ]) return queryset.filter(pk__in=taxon_pks) else: return queryset def taxa_with_conservation_criteria(self, queryset, name, value): """Return Taxa matching a conservation level. * The filter returns a list of ConservationCategories as ``value`` * The Taxon PKs are calculated from TaxonConservationListings with categories matching the list of categories in ``value`` * The queryset is filtered by the list of Taxon PKs matching the conservation level """ if value: taxon_pks = set([ x["taxon__pk"] for x in cons_models.TaxonConservationListing.objects.filter( category__in=value).values("taxon__pk") ]) return queryset.filter(pk__in=taxon_pks) else: return queryset
def test_default_field_with_queryset(self): qs = mock.NonCallableMock(spec=[]) f = ModelMultipleChoiceFilter(queryset=qs) field = f.field self.assertIsInstance(field, forms.ModelMultipleChoiceField) self.assertEqual(field.queryset, qs)
def test_default_field_without_queryset(self): f = ModelMultipleChoiceFilter() with self.assertRaises(TypeError): f.field
class F(FilterSet): author = ModelMultipleChoiceFilter(queryset=User.objects.all()) class Meta: model = Article fields = ['author']
def test_empty_choices(self): f = ModelMultipleChoiceFilter(queryset=User.objects.all(), null_value='null', null_label='NULL') self.assertEqual(list(f.field.choices), [ ('null', 'NULL'), ])