Konova filter mixins

* refactors konova/mixins.py into individual files in konova/mixins/...
pull/200/head
mpeltriaux 2 years ago
parent ca6770ec54
commit c07933a9bf

@ -10,7 +10,7 @@ from django.utils.translation import gettext_lazy as _
from django import forms from django import forms
from django.db.models import QuerySet, Q from django.db.models import QuerySet, Q
from konova.filters.mixins import ConservationOfficeTableFilterMixin from konova.filters.mixins.office import ConservationOfficeTableFilterMixin
from konova.filters.table_filters import QueryTableFilter, CheckboxTableFilter, SelectionTableFilter, AbstractTableFilter from konova.filters.table_filters import QueryTableFilter, CheckboxTableFilter, SelectionTableFilter, AbstractTableFilter

@ -1,414 +0,0 @@
"""
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, filter_q) -> QuerySet:
""" Filters the parcel entries by a given filter_q
Args:
queryset (QuerySet): The queryset
filter_q (Q): The Q-style filter expression
Returns:
"""
matching_parcels = Parcel.objects.filter(
filter_q
)
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(
Q(name__icontains=value) |
Q(key__icontains=value)
).distinct()
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,
Q(parcel_group__name__icontains=value) | Q(parcel_group__key__icontains=value),
)
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,
Q(flr=value),
)
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,
Q(flrstck_zhlr=value)
)
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,
Q(flrstck_nnr=value),
)
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(
Q(users__in=[self.user]) | # requesting user has access
Q(teams__in=self.user.shared_teams)
).distinct()
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

@ -0,0 +1,7 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""

@ -0,0 +1,33 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""
from django import forms
from django.db.models import QuerySet, Q
from django.utils.translation import gettext_lazy as _
import django_filters
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

@ -0,0 +1,209 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""
from django import forms
from django.db.models import QuerySet, Q
from django.utils.translation import gettext_lazy as _
import django_filters
from konova.models import Parcel, District
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, filter_q) -> QuerySet:
""" Filters the parcel entries by a given filter_q
Args:
queryset (QuerySet): The queryset
filter_q (Q): The Q-style filter expression
Returns:
"""
matching_parcels = Parcel.objects.filter(
filter_q
)
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(
Q(name__icontains=value) |
Q(key__icontains=value)
).distinct()
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,
Q(parcel_group__name__icontains=value) | Q(parcel_group__key__icontains=value),
)
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,
Q(flr=value),
)
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,
Q(flrstck_zhlr=value)
)
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,
Q(flrstck_nnr=value),
)
return queryset

@ -0,0 +1,41 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""
import django_filters
from django.db.models import QuerySet, Q
from intervention.inputs import DummyFilterInput
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)

@ -0,0 +1,77 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""
from dal_select2.widgets import ModelSelect2
from django.utils.translation import gettext_lazy as _
import django_filters
from codelist.models import KonovaCode
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
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
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

@ -0,0 +1,51 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""
from django import forms
from django.db.models import QuerySet
from django.utils.translation import gettext_lazy as _
import django_filters
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

@ -0,0 +1,57 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 18.08.22
"""
from django import forms
from django.db.models import Q, QuerySet
from django.utils.translation import gettext_lazy as _
import django_filters
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(
Q(users__in=[self.user]) | # requesting user has access
Q(teams__in=self.user.shared_teams)
).distinct()
else:
return queryset

@ -7,9 +7,12 @@ Created on: 12.01.22
""" """
import django_filters import django_filters
from konova.filters.mixins import RegistrationOfficeTableFilterMixin, ConservationOfficeTableFilterMixin, \ from konova.filters.mixins.file_number import FileNumberTableFilterMixin
KeywordTableFilterMixin, FileNumberTableFilterMixin, GeoReferencedTableFilterMixin, ShareableTableFilterMixin, \ from konova.filters.mixins.geo_reference import GeoReferencedTableFilterMixin
RecordableTableFilterMixin from konova.filters.mixins.keyword import KeywordTableFilterMixin
from konova.filters.mixins.office import ConservationOfficeTableFilterMixin, RegistrationOfficeTableFilterMixin
from konova.filters.mixins.record import RecordableTableFilterMixin
from konova.filters.mixins.share import ShareableTableFilterMixin
class AbstractTableFilter(django_filters.FilterSet): class AbstractTableFilter(django_filters.FilterSet):

Loading…
Cancel
Save