""" Author: Michel Peltriaux Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Contact: michel.peltriaux@sgdnord.rlp.de Created on: 12.01.22 """ import django_filters from django import forms from django.db.models import QuerySet, Q from django.utils.translation import gettext_lazy as _ from dal_select2.widgets import ModelSelect2 from codelist.models import KonovaCode from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID from intervention.inputs import DummyFilterInput from konova.models import Parcel, District class KeywordTableFilterMixin(django_filters.FilterSet): q = django_filters.Filter( method='filter_by_keyword', # Since we use a custom search bar in the template, we need to 'render' this filter # as 'anonymous' HiddenInput (no id, no name). This way our custom search bar's id and name won't be # overwritten with these id and name (which would be equal) # This way we can use the simple filter method mapping for a parameter without using a predefined widget! widget=DummyFilterInput(), ) class Meta: abstract = True def filter_by_keyword(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value of search bar input Args: queryset (): name (): value (): Returns: """ value = value.strip() # build filter expression q = Q(title__icontains=value) | Q(identifier__icontains=value) return queryset.filter(q) class FileNumberTableFilterMixin(django_filters.FilterSet): rf = django_filters.CharFilter( method="filter_file_number", label=_(""), label_suffix=_(""), widget=forms.TextInput( attrs={ "placeholder": _("File number"), "title": _("Search for file number"), "class": "form-control", } ), ) def filter_file_number(self, queryset, name, value) -> QuerySet: queryset = queryset.filter( Q(responsible__registration_file_number__icontains=value) | Q(responsible__conservation_file_number__icontains=value) ) return queryset class GeoReferencedTableFilterMixin(django_filters.FilterSet): """ A mixin for AbstractTableFilter Specialized on filtering GeoReferenced model types """ # Parcel gmrkng di = django_filters.CharFilter( method="filter_district", label=_(""), label_suffix=_(""), widget=forms.TextInput( attrs={ "placeholder": _("District"), "title": _("Search for district"), "class": "form-control", } ), ) # Parcel gmrkng pg = django_filters.CharFilter( method="filter_gmrkng", label=_(""), label_suffix=_(""), widget=forms.TextInput( attrs={ "placeholder": _("Parcel gmrkng"), "title": _("Search for parcel gmrkng"), "class": "form-control", } ), ) # Parcel p = django_filters.CharFilter( method="filter_parcel", label=_(""), label_suffix=_(""), widget=forms.TextInput( attrs={ "placeholder": _("Parcel"), "title": _("Search for parcel"), "class": "form-control", } ), ) # Parcel counter pc = django_filters.CharFilter( method="filter_parcel_counter", label=_(""), label_suffix=_(""), widget=forms.TextInput( attrs={ "placeholder": _("Parcel counter"), "title": _("Search for parcel counter"), "class": "form-control", } ), ) # Parcel counter pn = django_filters.CharFilter( method="filter_parcel_number", label=_(""), label_suffix=_(""), widget=forms.TextInput( attrs={ "placeholder": _("Parcel number"), "title": _("Search for parcel number"), "class": "form-control", } ), ) class Meta: abstract = True def _filter_parcel_reference(self, queryset, name, value, filter_value) -> QuerySet: """ Filters the parcel entries by a given filter_value. filter_value may already include further filter annotations like 'xy__icontains' Args: queryset (): name (): value (): filter_value (): Returns: """ _filter = { filter_value: value } matching_parcels = Parcel.objects.filter( **_filter ) related_geoms = matching_parcels.values( "geometries" ).distinct() queryset = queryset.filter( geometry__id__in=related_geoms ) return queryset def filter_district(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value for 'Gemarkung' Args: queryset (): name (): value (): Returns: """ matching_districts = District.objects.filter( krs=value ) matching_parcels = Parcel.objects.filter( district__in=matching_districts ) related_geoms = matching_parcels.values( "geometries" ).distinct() queryset = queryset.filter( geometry__id__in=related_geoms ) return queryset def filter_gmrkng(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value for 'Gemarkung' Args: queryset (): name (): value (): Returns: """ queryset = self._filter_parcel_reference(queryset, name, value, "gmrkng__istartswith") return queryset def filter_parcel(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value for 'Parcel' Args: queryset (): name (): value (): Returns: """ value = value.replace("-", "") queryset = self._filter_parcel_reference(queryset, name, value, "flr") return queryset def filter_parcel_counter(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value for 'Parcel' Args: queryset (): name (): value (): Returns: """ value = value.replace("-", "") queryset = self._filter_parcel_reference(queryset, name, value, "flrstck_zhlr") return queryset def filter_parcel_number(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value for 'Parcel' Args: queryset (): name (): value (): Returns: """ value = value.replace("-", "") queryset = self._filter_parcel_reference(queryset, name, value, "flrstck_nnr") return queryset class ShareableTableFilterMixin(django_filters.FilterSet): """ A mixin for AbstractTableFilter Specialized on filtering shareable model types """ sa = django_filters.BooleanFilter( method='filter_show_all', label=_("Show unshared"), label_suffix=_(""), widget=forms.CheckboxInput( attrs={ "class": "form-check-input", } ) ) class Meta: abstract = True def __init__(self, *args, **kwargs): self.user = kwargs.pop("user", None) if self.user is None: raise AttributeError("User must be set for further filtering!") super().__init__(*args, **kwargs) def filter_show_all(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value of 'show_all' setting Args: queryset (): name (): value (): Returns: """ if not value: return queryset.filter( users__in=[self.user], # requesting user has access ) else: return queryset class RecordableTableFilterMixin(django_filters.FilterSet): """ A mixin for AbstractTableFilter Specialized on filtering recordable model types """ sr = django_filters.BooleanFilter( method='filter_show_recorded', label=_("Show recorded"), label_suffix=_(""), widget=forms.CheckboxInput( attrs={ "class": "form-check-input", } ) ) class Meta: abstract = True def filter_show_recorded(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value of 'show_recorded' setting Args: queryset (): name (): value (): Returns: """ if not value: return queryset.filter( recorded=None, ) else: return queryset class RegistrationOfficeTableFilterMixin(django_filters.FilterSet): """ A mixin for AbstractTableFilter Specialized on filtering for related registration offices """ ro = django_filters.ModelChoiceFilter( method="filter_reg_office", label=_(""), label_suffix=_(""), queryset=KonovaCode.objects.filter( is_archived=False, is_leaf=True, code_lists__in=[CODELIST_REGISTRATION_OFFICE_ID], ), widget=ModelSelect2( url="codes-registration-office-autocomplete", attrs={ "data-placeholder": _("Registration office"), "title": _("Search for registration office"), "class": "", } ), ) def filter_reg_office(self, queryset, name, value): qs = queryset.filter( responsible__registration_office=value ) return qs class ConservationOfficeTableFilterMixin(django_filters.FilterSet): """ A mixin for AbstractTableFilter Specialized on filtering for related conservation offices """ co = django_filters.ModelChoiceFilter( method="filter_cons_office", label=_(""), label_suffix=_(""), queryset=KonovaCode.objects.filter( is_archived=False, is_leaf=True, code_lists__in=[CODELIST_CONSERVATION_OFFICE_ID], ), widget=ModelSelect2( url="codes-conservation-office-autocomplete", attrs={ "data-placeholder": _("Conservation office"), "title": _("Search for conservation office"), "class": "", } ), ) def filter_cons_office(self, queryset, name, value): qs = queryset.filter( responsible__conservation_office=value ) return qs