61_Extend_filter #64

Merged
mpeltriaux merged 9 commits from 61_Extend_filter into master 3 years ago

@ -8,20 +8,45 @@ Created on: 29.07.21
import django_filters
from django.utils.translation import gettext_lazy as _
from django import forms
from django.db.models import QuerySet
from django.db.models import QuerySet, Q
from intervention.filters import InterventionTableFilter
from konova.filters.mixins import ConservationOfficeTableFilterMixin
from konova.filters.table_filters import QueryTableFilter, CheckboxTableFilter, SelectionTableFilter, AbstractTableFilter
class CompensationTableFilter(InterventionTableFilter):
""" TableFilter for compensations
class SelectionCompensationTableFilter(SelectionTableFilter):
""" Specialization of regular SelectionTableFilter for compensation model
"""
def filter_reg_office(self, queryset, name, value):
return queryset.filter(
intervention__responsible__registration_office=value
)
def filter_cons_office(self, queryset, name, value):
return queryset.filter(
intervention__responsible__conservation_office=value
)
Based widely on InterventionTableFilter.
Just some minor changes for Compensation model.
class QueryCompensationTableFilter(QueryTableFilter):
""" Specialization of regular QueryTableFilter for compensation model
"""
def filter_file_number(self, queryset, name, value) -> QuerySet:
queryset = queryset.filter(
Q(intervention__responsible__registration_file_number__icontains=value) |
Q(intervention__responsible__conservation_file_number__icontains=value)
)
return queryset
class CheckboxCompensationTableFilter(CheckboxTableFilter):
""" Specialization of regular CheckboxTableFilter for compensation model
"""
def _filter_show_all(self, queryset, name, value) -> QuerySet:
def filter_show_all(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_all' setting
Args:
@ -39,7 +64,7 @@ class CompensationTableFilter(InterventionTableFilter):
else:
return queryset
def _filter_show_recorded(self, queryset, name, value) -> QuerySet:
def filter_show_recorded(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_recorded' setting
Args:
@ -58,21 +83,51 @@ class CompensationTableFilter(InterventionTableFilter):
return queryset
class EcoAccountTableFilter(InterventionTableFilter):
""" TableFilter for eco accounts
class CompensationTableFilter(AbstractTableFilter):
""" TableFilter for compensations
Based widely on InterventionTableFilter.
Just some minor changes for EcoAccount model.
Just some minor changes for Compensation model.
"""
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None)
# Overwrite all filters for special needs of compensations
self.selection_filter = SelectionCompensationTableFilter(
data=request_data,
queryset=qs,
)
self.query_filter = QueryCompensationTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxCompensationTableFilter(
user=user,
data=request_data,
queryset=self.query_filter.qs,
)
# Overwrite final queryset as well
self.qs = self.checkbox_filter.qs
class CheckboxEcoAccountTableFilter(CheckboxTableFilter):
sr = django_filters.BooleanFilter(
method='_filter_only_show_unrecorded',
method='filter_only_show_unrecorded',
label=_("Show only unrecorded"),
label_suffix=_(""),
widget=forms.CheckboxInput()
widget=forms.CheckboxInput(
attrs={
"class": "form-check-input",
}
)
)
def _filter_show_all(self, queryset, name, value) -> QuerySet:
def filter_show_all(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_all' setting
Args:
@ -90,7 +145,7 @@ class EcoAccountTableFilter(InterventionTableFilter):
else:
return queryset
def _filter_only_show_unrecorded(self, queryset, name, value) -> QuerySet:
def filter_only_show_unrecorded(self, queryset, name, value) -> QuerySet:
""" Filters queryset depending on value of 'show_recorded' setting
Args:
@ -107,3 +162,40 @@ class EcoAccountTableFilter(InterventionTableFilter):
)
else:
return queryset
class SelectionEcoAccountTableFilter(ConservationOfficeTableFilterMixin):
""" Special selection table filter for eco accounts
EcoAccounts only need a selection filter for conservation office
"""
pass
class EcoAccountTableFilter(AbstractTableFilter):
""" TableFilter for eco accounts
"""
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None)
# Pipe the queryset through all needed filters
self.selection_filter = SelectionEcoAccountTableFilter(
data=request_data,
queryset=qs,
)
self.query_filter = QueryTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxEcoAccountTableFilter(
user=user,
data=request_data,
queryset=self.query_filter.qs,
)
# Overwrite the final queryset result
self.qs = self.checkbox_filter.qs

@ -16,11 +16,11 @@ from django.utils.translation import gettext_lazy as _
from compensation.filters import CompensationTableFilter, EcoAccountTableFilter
from compensation.models import Compensation, EcoAccount
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils.tables import BaseTable
from konova.utils.tables import BaseTable, TableRenderMixin
import django_tables2 as tables
class CompensationTable(BaseTable):
class CompensationTable(BaseTable, TableRenderMixin):
id = tables.Column(
verbose_name=_("Identifier"),
orderable=True,
@ -67,7 +67,8 @@ class CompensationTable(BaseTable):
data=request.GET,
queryset=qs,
)
super().__init__(request, self.filter, *args, **kwargs)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
def render_id(self, value, record: Compensation):
""" Renders the id column for a compensation
@ -161,7 +162,7 @@ class CompensationTable(BaseTable):
return format_html(html)
class EcoAccountTable(BaseTable):
class EcoAccountTable(BaseTable, TableRenderMixin):
id = tables.Column(
verbose_name=_("Identifier"),
orderable=True,
@ -207,7 +208,8 @@ class EcoAccountTable(BaseTable):
data=request.GET,
queryset=qs,
)
super().__init__(request, self.filter, *args, **kwargs)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
def render_id(self, value, record: EcoAccount):
""" Renders the id column for an eco account

@ -5,8 +5,6 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 19.08.21
"""
from django.db.models import QuerySet
from compensation.filters import EcoAccountTableFilter

@ -14,12 +14,12 @@ from django.urls import reverse
import django_tables2 as tables
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils.tables import BaseTable
from konova.utils.tables import BaseTable, TableRenderMixin
from ema.filters import EmaTableFilter
from ema.models import Ema
class EmaTable(BaseTable):
class EmaTable(BaseTable, TableRenderMixin):
"""
Since EMA and compensation are basically the same, we can reuse CompensationTableFilter and extend the EMA filter
in the future by inheriting.
@ -65,7 +65,8 @@ class EmaTable(BaseTable):
data=request.GET,
queryset=qs,
)
super().__init__(request, self.filter, *args, **kwargs)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
def render_id(self, value, record: Ema):
""" Renders the id column for a EMA

@ -5,119 +5,29 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 22.07.21
"""
import django_filters
from django import forms
from django.contrib.auth.models import User
from django.db.models import QuerySet, Q
from konova.filters.table_filters import AbstractTableFilter, SelectionTableFilter, QueryTableFilter, CheckboxTableFilter
from django.utils.translation import gettext_lazy as _
from intervention.inputs import DummyFilterInput
from intervention.models import Intervention
class InterventionTableFilter(django_filters.FilterSet):
""" TableFilter for Intervention model
"""
sa = django_filters.BooleanFilter(
method='_filter_show_all',
label=_("Show unshared"),
label_suffix=_(""),
widget=forms.CheckboxInput()
)
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(),
)
sr = django_filters.BooleanFilter(
method='_filter_show_recorded',
label=_("Show recorded"),
label_suffix=_(""),
widget=forms.CheckboxInput()
)
# Gemarkung ##ToDo
g = django_filters.CharFilter(
field_name="name",
lookup_expr="icontains",
label=_(""),
label_suffix=_(""),
widget=forms.TextInput(
attrs={
"placeholder": _("District"),
"title": _("Search for district")
}
),
)
# Kreis
## ToDo
# Flur
## ToDo
# Zähler
## ToDo
# Nenner
## ToDo
class Meta:
model = Intervention
fields = []
def __init__(self, user: User, *args, **kwargs):
self.user = user
class InterventionTableFilter(AbstractTableFilter):
def __init__(self, user=None, *args, **kwargs):
super().__init__(*args, **kwargs)
self.user = user
qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None)
# Pipe the queryset through all needed filters
self.selection_filter = SelectionTableFilter(
data=request_data,
queryset=qs,
)
self.query_filter = QueryTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxTableFilter(
user=user,
data=request_data,
queryset=self.query_filter.qs,
)
self.qs = self.checkbox_filter.qs
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)
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
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

@ -14,11 +14,11 @@ from django.utils.translation import gettext_lazy as _
from intervention.filters import InterventionTableFilter
from intervention.models import Intervention
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT, DEFAULT_DATE_FORMAT
from konova.utils.tables import BaseTable
from konova.utils.tables import BaseTable, TableRenderMixin
import django_tables2 as tables
class InterventionTable(BaseTable):
class InterventionTable(BaseTable, TableRenderMixin):
id = tables.Column(
verbose_name=_("Identifier"),
orderable=True,
@ -71,7 +71,8 @@ class InterventionTable(BaseTable):
data=request.GET,
queryset=qs,
)
super().__init__(request, self.filter, *args, **kwargs)
kwargs["queryset"] = self.filter.qs
super().__init__(request, *args, **kwargs)
def render_id(self, value, record: Intervention):
""" Renders the id column for an intervention

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

@ -0,0 +1,406 @@
"""
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

@ -0,0 +1,50 @@
"""
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 konova.filters.mixins import RegistrationOfficeTableFilterMixin, ConservationOfficeTableFilterMixin, \
KeywordTableFilterMixin, FileNumberTableFilterMixin, GeoReferencedTableFilterMixin, ShareableTableFilterMixin, \
RecordableTableFilterMixin
class AbstractTableFilter(django_filters.FilterSet):
""" Base TableFilter for all models
"""
selection_filter = None
query_filter = None
checkbox_filter = None
qs = None
user = None
class Meta:
abstract = True
class SelectionTableFilter(RegistrationOfficeTableFilterMixin,
ConservationOfficeTableFilterMixin):
""" TableFilter holding different filter options for selection related filtering
"""
pass
class QueryTableFilter(KeywordTableFilterMixin,
FileNumberTableFilterMixin,
GeoReferencedTableFilterMixin):
""" TableFilter holding different filter options for query related filtering
"""
pass
class CheckboxTableFilter(ShareableTableFilterMixin, RecordableTableFilterMixin):
""" TableFilter holding different filter options for checkbox related filtering
"""
pass

@ -110,9 +110,13 @@ class Geometry(BaseResource):
underlying_parcels = []
for result in fetched_parcels:
fetched_parcel = result[typename]
# There could be parcels which include the word 'Flur',
# which needs to be deleted and just keep the numerical values
## THIS CAN BE REMOVED IN THE FUTURE, WHEN 'Flur' WON'T OCCUR ANYMORE!
flr_val = fetched_parcel["ave:flur"].replace("Flur ", "")
parcel_obj = Parcel.objects.get_or_create(
gmrkng=fetched_parcel["ave:gemarkung"],
flr=fetched_parcel["ave:flur"],
flr=flr_val,
flrstck_nnr=fetched_parcel['ave:flstnrnen'],
flrstck_zhlr=fetched_parcel['ave:flstnrzae'],
)[0]

@ -404,6 +404,7 @@ class AutocompleteTestCase(BaseViewTestCase):
cls.atcmplt_code_comp_process = reverse("codes-process-type-autocomplete")
cls.atcmplt_code_comp_reg_off = reverse("codes-registration-office-autocomplete")
cls.atcmplt_code_comp_cons_off = reverse("codes-conservation-office-autocomplete")
cls.atcmplt_code_share_user = reverse("share-user-autocomplete")
def _test_views_anonymous_user(self):
# ATTENTION: As of the current state of django-autocomplete-light, there is no way to check on authenticated
@ -421,6 +422,7 @@ class AutocompleteTestCase(BaseViewTestCase):
self.atcmplt_code_comp_process,
self.atcmplt_code_comp_reg_off,
self.atcmplt_code_comp_cons_off,
self.atcmplt_code_share_user,
]
self.assert_url_fail(client, urls)

@ -5,15 +5,13 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 25.11.20
"""
import uuid
from django import forms
from django.core.paginator import PageNotAnInteger, EmptyPage
from django.http import HttpRequest
from django.utils.html import format_html
import django_tables2 as tables
from konova.forms import BaseForm
from konova.models import BaseObject
from konova.settings import PAGE_SIZE_DEFAULT, PAGE_PARAM, RESULTS_PER_PAGE_PARAM, PAGE_SIZE_OPTIONS
@ -31,10 +29,8 @@ class BaseTable(tables.tables.Table):
"class": "table table-hover table-responsive-md table-responsive-sm",
}
def __init__(self, request: HttpRequest = None, filter_set=None, queryset=None, *args, **kwargs):
def __init__(self, request: HttpRequest = None, queryset=None, *args, **kwargs):
self.user = request.user or None
if filter_set is not None:
queryset = filter_set.qs
kwargs["data"] = queryset
kwargs["request"] = request
super().__init__(*args, **kwargs)
@ -149,22 +145,21 @@ class BaseTable(tables.tables.Table):
)
class ChoicesColumnForm(BaseForm):
select = forms.ChoiceField(
choices=[],
label="",
label_suffix="",
widget=forms.Select(
attrs={
"onchange": "submit();",
}
)
)
class TableRenderMixin:
""" Holds different render methods for general purposes
def __init__(self, *args, **kwargs):
self.action_url = kwargs.pop("action_url", None)
self.choices = kwargs.pop("choices", [])
super().__init__(*args, **kwargs)
self.auto_id += "_" + str(uuid.uuid4())
if len(self.choices) > 0:
self.fields["select"].choices = self.choices
"""
def render_t(self, value, record: BaseObject):
""" Renders a BaseObject title
Args:
value ():
record ():
Returns:
"""
max_length = 75
if len(value) > max_length:
value = f"{value[:max_length]}..."
return value

Binary file not shown.

@ -3,23 +3,26 @@
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#: compensation/filters.py:71 compensation/forms/modalForms.py:34
#: compensation/filters.py:91 compensation/forms/modalForms.py:34
#: compensation/forms/modalForms.py:45 compensation/forms/modalForms.py:61
#: compensation/forms/modalForms.py:238 compensation/forms/modalForms.py:316
#: intervention/filters.py:26 intervention/filters.py:40
#: intervention/filters.py:47 intervention/filters.py:48
#: intervention/forms/forms.py:52 intervention/forms/forms.py:154
#: intervention/forms/forms.py:166 intervention/forms/modalForms.py:125
#: intervention/forms/modalForms.py:138 intervention/forms/modalForms.py:151
#: konova/forms.py:140 konova/forms.py:241 konova/forms.py:312
#: konova/forms.py:339 konova/forms.py:349 konova/forms.py:362
#: konova/forms.py:374 konova/forms.py:392 user/forms.py:38
#: konova/filters.py:63 konova/filters.py:64 konova/filters.py:91
#: konova/filters.py:92 konova/filters.py:104 konova/filters.py:105
#: konova/filters.py:117 konova/filters.py:118 konova/filters.py:130
#: konova/filters.py:131 konova/filters.py:144 konova/filters.py:145
#: konova/filters.py:280 konova/filters.py:324 konova/forms.py:140
#: konova/forms.py:241 konova/forms.py:312 konova/forms.py:339
#: konova/forms.py:349 konova/forms.py:362 konova/forms.py:374
#: konova/forms.py:392 user/forms.py:38
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-01-07 15:32+0100\n"
"POT-Creation-Date: 2022-01-11 17:07+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -145,7 +148,7 @@ msgstr "Geprüft"
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:9
#: analysis/templates/analysis/reports/includes/intervention/laws.html:20
#: analysis/templates/analysis/reports/includes/old_data/amount.html:18
#: compensation/tables.py:41 compensation/tables.py:181
#: compensation/tables.py:41 compensation/tables.py:182
#: compensation/templates/compensation/detail/compensation/view.html:77
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:31
#: compensation/templates/compensation/detail/eco_account/view.html:44
@ -231,7 +234,7 @@ msgstr "Kompensationsart"
#: analysis/templates/analysis/reports/includes/intervention/compensated_by.html:15
#: analysis/templates/analysis/reports/includes/old_data/amount.html:29
#: compensation/tables.py:84
#: compensation/tables.py:85
#: compensation/templates/compensation/detail/compensation/view.html:19
#: konova/templates/konova/home.html:49 templates/navbars/navbar.html:28
msgid "Compensation"
@ -276,14 +279,14 @@ msgstr "Typ"
#: analysis/templates/analysis/reports/includes/old_data/amount.html:24
#: intervention/forms/modalForms.py:306 intervention/forms/modalForms.py:313
#: intervention/tables.py:88
#: intervention/tables.py:89
#: intervention/templates/intervention/detail/view.html:19
#: konova/templates/konova/home.html:11 templates/navbars/navbar.html:22
msgid "Intervention"
msgstr "Eingriff"
#: analysis/templates/analysis/reports/includes/old_data/amount.html:34
#: compensation/tables.py:224
#: compensation/tables.py:226
#: compensation/templates/compensation/detail/eco_account/view.html:19
#: intervention/forms/modalForms.py:279 intervention/forms/modalForms.py:286
#: konova/templates/konova/home.html:88 templates/navbars/navbar.html:34
@ -298,12 +301,12 @@ msgstr "Altfälle"
msgid "Before"
msgstr "Vor"
#: compensation/filters.py:70
#: compensation/filters.py:90
msgid "Show only unrecorded"
msgstr "Nur unverzeichnete anzeigen"
#: compensation/forms/forms.py:32 compensation/tables.py:25
#: compensation/tables.py:166 ema/tables.py:28 intervention/forms/forms.py:26
#: compensation/tables.py:167 ema/tables.py:28 intervention/forms/forms.py:26
#: intervention/tables.py:23
#: intervention/templates/intervention/detail/includes/compensations.html:30
msgid "Identifier"
@ -314,7 +317,7 @@ msgid "Generated automatically"
msgstr "Automatisch generiert"
#: compensation/forms/forms.py:44 compensation/tables.py:30
#: compensation/tables.py:171
#: compensation/tables.py:172
#: compensation/templates/compensation/detail/compensation/includes/documents.html:28
#: compensation/templates/compensation/detail/compensation/view.html:31
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
@ -633,65 +636,65 @@ msgstr ""
"Es wurde bereits mehr Fläche abgebucht, als Sie nun als abbuchbar einstellen "
"wollen. Kontaktieren Sie die für die Abbuchungen verantwortlichen Nutzer!"
#: compensation/tables.py:47 compensation/tables.py:187 ema/tables.py:44
#: compensation/tables.py:47 compensation/tables.py:188 ema/tables.py:44
#: intervention/tables.py:51
msgid "Editable"
msgstr "Freigegeben"
#: compensation/tables.py:53 compensation/tables.py:193 ema/tables.py:50
#: compensation/tables.py:53 compensation/tables.py:194 ema/tables.py:50
#: intervention/tables.py:57
msgid "Last edit"
msgstr "Zuletzt bearbeitet"
#: compensation/tables.py:84 compensation/tables.py:224 ema/tables.py:82
#: intervention/tables.py:88
#: compensation/tables.py:85 compensation/tables.py:226 ema/tables.py:83
#: intervention/tables.py:89
msgid "Open {}"
msgstr "Öffne {}"
#: compensation/tables.py:105 intervention/tables.py:107
#: compensation/tables.py:106 intervention/tables.py:108
msgid "Not checked yet"
msgstr "Noch nicht geprüft"
#: compensation/tables.py:110 intervention/tables.py:112
#: compensation/tables.py:111 intervention/tables.py:113
msgid "Checked on {} by {}"
msgstr "Am {} von {} geprüft worden"
#: compensation/tables.py:129
#: compensation/tables.py:130
#: compensation/templates/compensation/detail/compensation/view.html:80
#: compensation/templates/compensation/detail/eco_account/includes/deductions.html:56
#: compensation/templates/compensation/detail/eco_account/view.html:47
#: ema/tables.py:101 ema/templates/ema/detail/view.html:38
#: intervention/tables.py:131
#: ema/tables.py:102 ema/templates/ema/detail/view.html:38
#: intervention/tables.py:132
#: intervention/templates/intervention/detail/view.html:85
msgid "Not recorded yet"
msgstr "Noch nicht verzeichnet"
#: compensation/tables.py:134 compensation/tables.py:262 ema/tables.py:106
#: intervention/tables.py:136
#: compensation/tables.py:135 compensation/tables.py:264 ema/tables.py:107
#: intervention/tables.py:137
msgid "Recorded on {} by {}"
msgstr "Am {} von {} verzeichnet worden"
#: compensation/tables.py:158 compensation/tables.py:284 ema/tables.py:129
#: intervention/tables.py:159
#: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:130
#: intervention/tables.py:160
msgid "Full access granted"
msgstr "Für Sie freigegeben - Datensatz kann bearbeitet werden"
#: compensation/tables.py:158 compensation/tables.py:284 ema/tables.py:129
#: intervention/tables.py:159
#: compensation/tables.py:159 compensation/tables.py:286 ema/tables.py:130
#: intervention/tables.py:160
msgid "Access not granted"
msgstr "Nicht freigegeben - Datensatz nur lesbar"
#: compensation/tables.py:176
#: compensation/tables.py:177
#: compensation/templates/compensation/detail/eco_account/view.html:35
#: konova/templates/konova/widgets/progressbar.html:3
msgid "Available"
msgstr "Verfügbar"
#: compensation/tables.py:202
#: compensation/tables.py:203
msgid "Eco Accounts"
msgstr "Ökokonten"
#: compensation/tables.py:257
#: compensation/tables.py:259
msgid "Not recorded yet. Can not be used for deductions, yet."
msgstr ""
"Noch nicht verzeichnet. Kann noch nicht für Abbuchungen genutzt werden."
@ -1177,7 +1180,7 @@ msgstr ""
"Maßnahmen aus Ersatzzahlungen, die nach 2015 rechtskräftig wurden, werden "
"durch die Stiftung Natur und Umwelt verwaltet."
#: ema/tables.py:82 templates/navbars/navbar.html:43
#: ema/tables.py:83 templates/navbars/navbar.html:43
msgid "EMA"
msgstr ""
@ -1197,22 +1200,6 @@ msgstr "EMA {} bearbeitet"
msgid "EMA removed"
msgstr "EMA entfernt"
#: intervention/filters.py:25
msgid "Show unshared"
msgstr "Nicht freigegebene anzeigen"
#: intervention/filters.py:39
msgid "Show recorded"
msgstr "Verzeichnete anzeigen"
#: intervention/filters.py:51
msgid "District"
msgstr "Gemarkung"
#: intervention/filters.py:52
msgid "Search for district"
msgstr "Nach Gemarkung suchen"
#: intervention/forms/forms.py:44
msgid "Construction XY; Location ABC"
msgstr "Bauvorhaben XY; Flur ABC"
@ -1382,11 +1369,11 @@ msgstr ""
msgid "Revocation"
msgstr "Widerspruch"
#: intervention/tables.py:176
#: intervention/tables.py:177
msgid "No revocation"
msgstr "Kein Widerspruch"
#: intervention/tables.py:182
#: intervention/tables.py:183
msgid "Revocation from {}, added on {} by {}"
msgstr "Widerspruch vom {}, am {} von {} hinzugefügt"
@ -1521,6 +1508,62 @@ msgstr ""
"somit nichts eingeben, bearbeiten oder sonstige Aktionen ausführen. "
"Kontaktieren Sie bitte einen Administrator. +++"
#: konova/filters.py:67
msgid "File number"
msgstr "Aktenzeichen"
#: konova/filters.py:68
msgid "Search for file number"
msgstr "Nach Aktenzeichen suchen"
#: konova/filters.py:95
msgid "District"
msgstr "Kreis"
#: konova/filters.py:96
msgid "Search for district"
msgstr "Nach Kreis suchen"
#: konova/filters.py:108
msgid "Parcel gmrkng"
msgstr "Gemarkung"
#: konova/filters.py:109
msgid "Search for parcel gmrkng"
msgstr "Nach Gemarkung suchen"
#: konova/filters.py:121 konova/templates/konova/includes/parcels.html:18
msgid "Parcel"
msgstr "Flur"
#: konova/filters.py:122
msgid "Search for parcel"
msgstr "Nach Flur suchen"
#: konova/filters.py:134 konova/templates/konova/includes/parcels.html:19
msgid "Parcel counter"
msgstr "Flurstückzähler"
#: konova/filters.py:135
msgid "Search for parcel counter"
msgstr "Nach Flurstückzähler suchen"
#: konova/filters.py:148 konova/templates/konova/includes/parcels.html:20
msgid "Parcel number"
msgstr "Flurstücknenner"
#: konova/filters.py:149
msgid "Search for parcel number"
msgstr "Nach Flurstücknenner suchen"
#: konova/filters.py:279
msgid "Show unshared"
msgstr "Nicht freigegebene anzeigen"
#: konova/filters.py:323
msgid "Show recorded"
msgstr "Verzeichnete anzeigen"
#: konova/forms.py:37 templates/form/collapsable/form.html:62
msgid "Save"
msgstr "Speichern"
@ -1687,18 +1730,6 @@ msgstr "Kreis"
msgid "Gemarkung"
msgstr "Gemarkung"
#: konova/templates/konova/includes/parcels.html:18
msgid "Parcel"
msgstr "Flur"
#: konova/templates/konova/includes/parcels.html:19
msgid "Parcel counter"
msgstr "Flurstückzähler"
#: konova/templates/konova/includes/parcels.html:20
msgid "Parcel number"
msgstr "Flurstücknenner"
#: konova/templates/konova/widgets/generate-content-input.html:6
msgid "Generate new"
msgstr "Neu generieren"
@ -1899,11 +1930,11 @@ msgstr "Starte Suche"
msgid "Results per page"
msgstr "Treffer pro Seite"
#: templates/generic_index.html:82 templates/generic_index.html:88
#: templates/generic_index.html:82 templates/generic_index.html:99
msgid "Filter"
msgstr ""
#: templates/generic_index.html:90
#: templates/generic_index.html:101
msgid "Apply filter"
msgstr "Filter anwenden"

@ -0,0 +1,5 @@
{% for field in form %}
<div class="form-check form-check-inline">
{{field}} <label class="form-check-label" for="id_{{field.name}}">{{field.label}}</label>
</div>
{% endfor %}

@ -0,0 +1,10 @@
<div class="form-row align-items-center">
{% for field in form %}
{% if not field.is_hidden %}
<div class="col-auto">
{{field}}
</div>
{% else %}
{% endif %}
{% endfor %}
</div>

@ -3,6 +3,16 @@
{% load django_tables2 %}
{% load i18n static fontawesome_5 %}
{% block head %}
{% comment %}
dal documentation (django-autocomplete-light) states using form.media for adding needed scripts.
This does not work properly with modal forms, as the scripts are not loaded properly inside the modal.
Therefore the script linkages from form.media have been extracted and put inside dal/scripts.html to ensure
these scripts are loaded when needed.
{% endcomment %}
{% include 'dal/scripts.html' %}
{% endblock %}
{% block body %}
<div class="col-md">
{% if table.title %}
@ -41,7 +51,7 @@
<div class="row my-1">
<div class="col-sm-12 col-md-8 col-lg-6">
<div class="input-group">
<input id="id_{{table.filter.filters.q.field_name}}" name="{{table.filter.filters.q.field_name}}" type="text" class="form-control" aria-label="{% trans 'Search for keywords' %}" placeholder="{% trans 'Search' %}" value="{{ request.GET.q }}">
<input id="id_{{table.filter.query_filter.filters.q.field_name}}" name="{{table.filter.query_filter.filters.q.field_name}}" type="text" class="form-control" aria-label="{% trans 'Search for keywords' %}" placeholder="{% trans 'Search' %}" value="{{ request.GET.q }}">
<div class="input-group-append" title="{% trans 'Start search' %}">
<button type="submit" class="btn btn-default input-group-text">
<span class="">
@ -82,11 +92,32 @@
</div>
<div id="filter" class="collapse" aria-labelledby="filterHeader">
<div class="card-body">
{{ table.filter.form.as_p }}
<button class="btn btn-default" title="{% trans 'Filter' %}">
{% fa5_icon 'filter' %}
{% trans 'Apply filter' %}
</button>
<div class="">
<div class="">
{% with table.filter.selection_filter.form as form %}
{% include 'filter/query_filter.html' %}
{% endwith %}
</div>
<hr>
<div class="mt-3">
{% with table.filter.query_filter.form as form %}
{% include 'filter/query_filter.html' %}
{% endwith %}
</div>
<hr>
<div class="mt-3">
{% with table.filter.checkbox_filter.form as form %}
{% include 'filter/checkbox_filter.html' %}
{% endwith %}
</div>
<hr>
<div class="mt-3">
<button class="btn btn-default" title="{% trans 'Filter' %}">
{% fa5_icon 'filter' %}
{% trans 'Apply filter' %}
</button>
</div>
</div>
</div>
</div>
</div>

Loading…
Cancel
Save