Compare commits
4 Commits
5bca8fc8f7
...
96f2e77972
Author | SHA1 | Date | |
---|---|---|---|
96f2e77972 | |||
4c5e170b85 | |||
d57478ee09 | |||
834fa8dbd4 |
@ -10,7 +10,23 @@ from django.utils.translation import gettext_lazy as _
|
||||
from django import forms
|
||||
from django.db.models import QuerySet, Q
|
||||
|
||||
from konova.filters import QueryTableFilter, CheckboxTableFilter
|
||||
from konova.filters.mixins import ConservationOfficeTableFilterMixin
|
||||
from konova.filters.table_filters import QueryTableFilter, CheckboxTableFilter, SelectionTableFilter, AbstractTableFilter
|
||||
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
class QueryCompensationTableFilter(QueryTableFilter):
|
||||
@ -67,32 +83,35 @@ class CheckboxCompensationTableFilter(CheckboxTableFilter):
|
||||
return queryset
|
||||
|
||||
|
||||
class CompensationTableFilter:
|
||||
class CompensationTableFilter(AbstractTableFilter):
|
||||
""" TableFilter for compensations
|
||||
|
||||
Based widely on InterventionTableFilter.
|
||||
Just some minor changes for Compensation model.
|
||||
|
||||
"""
|
||||
query_filter = None
|
||||
checkbox_filter = None
|
||||
qs = None
|
||||
def __init__(self, user=None, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.get("user", None)
|
||||
self.user = user
|
||||
qs = kwargs.get("queryset", None)
|
||||
request_data = kwargs.get("data", None)
|
||||
|
||||
self.query_filter = QueryCompensationTableFilter(
|
||||
user=user,
|
||||
# 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
|
||||
|
||||
|
||||
@ -145,27 +164,38 @@ class CheckboxEcoAccountTableFilter(CheckboxTableFilter):
|
||||
return queryset
|
||||
|
||||
|
||||
class EcoAccountTableFilter:
|
||||
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
|
||||
|
||||
"""
|
||||
query_filter = None
|
||||
checkbox_filter = None
|
||||
qs = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.get("user", None)
|
||||
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)
|
||||
|
||||
self.query_filter = QueryTableFilter(
|
||||
user=user,
|
||||
# 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,
|
||||
@ -162,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,
|
||||
|
@ -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.
|
||||
|
@ -5,27 +5,29 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 22.07.21
|
||||
|
||||
"""
|
||||
from konova.filters import QueryTableFilter, CheckboxTableFilter
|
||||
from konova.filters.table_filters import AbstractTableFilter, SelectionTableFilter, QueryTableFilter, CheckboxTableFilter
|
||||
|
||||
|
||||
class InterventionTableFilter:
|
||||
query_filter = None
|
||||
checkbox_filter = None
|
||||
qs = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
user = kwargs.get("user", None)
|
||||
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)
|
||||
|
||||
self.query_filter = QueryTableFilter(
|
||||
user=user,
|
||||
# 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
|
||||
|
||||
|
@ -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,
|
||||
|
7
konova/filters/__init__.py
Normal file
7
konova/filters/__init__.py
Normal file
@ -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
|
||||
|
||||
"""
|
@ -2,31 +2,21 @@
|
||||
Author: Michel Peltriaux
|
||||
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
|
||||
Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 11.01.22
|
||||
Created on: 12.01.22
|
||||
|
||||
"""
|
||||
import django_filters
|
||||
from django import forms
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.contrib.auth.models import User
|
||||
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 AbstractTableFilter(django_filters.FilterSet):
|
||||
""" TableFilter for Intervention model
|
||||
|
||||
"""
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __init__(self, user: User, *args, **kwargs):
|
||||
self.user = user
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class KeywordTableFilterMixin(django_filters.FilterSet):
|
||||
q = django_filters.Filter(
|
||||
method='filter_by_keyword',
|
||||
@ -289,9 +279,10 @@ class ShareableTableFilterMixin(django_filters.FilterSet):
|
||||
abstract = True
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*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
|
||||
@ -351,18 +342,65 @@ class RecordableTableFilterMixin(django_filters.FilterSet):
|
||||
return queryset
|
||||
|
||||
|
||||
class QueryTableFilter(AbstractTableFilter,
|
||||
KeywordTableFilterMixin,
|
||||
FileNumberTableFilterMixin,
|
||||
GeoReferencedTableFilterMixin):
|
||||
""" TableFilter holding different filter options for query related filtering
|
||||
class RegistrationOfficeTableFilterMixin(django_filters.FilterSet):
|
||||
""" A mixin for AbstractTableFilter
|
||||
|
||||
Specialized on filtering for related registration offices
|
||||
|
||||
"""
|
||||
pass
|
||||
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 CheckboxTableFilter(AbstractTableFilter, ShareableTableFilterMixin, RecordableTableFilterMixin):
|
||||
""" TableFilter holding different filter options for checkbox related filtering
|
||||
class ConservationOfficeTableFilterMixin(django_filters.FilterSet):
|
||||
""" A mixin for AbstractTableFilter
|
||||
|
||||
Specialized on filtering for related conservation offices
|
||||
|
||||
"""
|
||||
pass
|
||||
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
|
50
konova/filters/table_filters.py
Normal file
50
konova/filters/table_filters.py
Normal file
@ -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
|
@ -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
|
||||
|
||||
|
||||
@ -147,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
|
@ -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 %}
|
||||
@ -82,22 +92,31 @@
|
||||
</div>
|
||||
<div id="filter" class="collapse" aria-labelledby="filterHeader">
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
{% with table.filter.query_filter.form as form %}
|
||||
{% include 'filter/query_filter.html' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
{% with table.filter.checkbox_filter.form as form %}
|
||||
{% include 'filter/checkbox_filter.html' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
<hr>
|
||||
<div class="row mt-3">
|
||||
<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>
|
||||
|
Loading…
Reference in New Issue
Block a user