Compare commits

..

No commits in common. "96f2e77972bb851cafeffa79ed005ab93ab36d1b" and "5bca8fc8f740198c91d7d152469a2ada128fdde3" have entirely different histories.

12 changed files with 99 additions and 242 deletions

View File

@ -10,23 +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 import QueryTableFilter, CheckboxTableFilter
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): class QueryCompensationTableFilter(QueryTableFilter):
@ -83,35 +67,32 @@ class CheckboxCompensationTableFilter(CheckboxTableFilter):
return queryset return queryset
class CompensationTableFilter(AbstractTableFilter): class CompensationTableFilter:
""" TableFilter for compensations """ TableFilter for compensations
Based widely on InterventionTableFilter. Based widely on InterventionTableFilter.
Just some minor changes for Compensation model. Just some minor changes for Compensation model.
""" """
def __init__(self, user=None, *args, **kwargs): query_filter = None
super().__init__(*args, **kwargs) checkbox_filter = None
qs = None
self.user = user def __init__(self, *args, **kwargs):
user = kwargs.get("user", None)
qs = kwargs.get("queryset", None) qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None) request_data = kwargs.get("data", None)
# Overwrite all filters for special needs of compensations self.query_filter = QueryCompensationTableFilter(
self.selection_filter = SelectionCompensationTableFilter( user=user,
data=request_data, data=request_data,
queryset=qs, queryset=qs,
) )
self.query_filter = QueryCompensationTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxCompensationTableFilter( self.checkbox_filter = CheckboxCompensationTableFilter(
user=user, user=user,
data=request_data, data=request_data,
queryset=self.query_filter.qs, queryset=self.query_filter.qs,
) )
# Overwrite final queryset as well
self.qs = self.checkbox_filter.qs self.qs = self.checkbox_filter.qs
@ -164,38 +145,27 @@ class CheckboxEcoAccountTableFilter(CheckboxTableFilter):
return queryset return queryset
class SelectionEcoAccountTableFilter(ConservationOfficeTableFilterMixin): class EcoAccountTableFilter:
""" Special selection table filter for eco accounts
EcoAccounts only need a selection filter for conservation office
"""
pass
class EcoAccountTableFilter(AbstractTableFilter):
""" TableFilter for eco accounts """ TableFilter for eco accounts
""" """
def __init__(self, user=None, *args, **kwargs): query_filter = None
super().__init__(*args, **kwargs) checkbox_filter = None
self.user = user qs = None
def __init__(self, *args, **kwargs):
user = kwargs.get("user", None)
qs = kwargs.get("queryset", None) qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None) request_data = kwargs.get("data", None)
# Pipe the queryset through all needed filters self.query_filter = QueryTableFilter(
self.selection_filter = SelectionEcoAccountTableFilter( user=user,
data=request_data, data=request_data,
queryset=qs, queryset=qs,
) )
self.query_filter = QueryTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxEcoAccountTableFilter( self.checkbox_filter = CheckboxEcoAccountTableFilter(
user=user, user=user,
data=request_data, data=request_data,
queryset=self.query_filter.qs, queryset=self.query_filter.qs,
) )
# Overwrite the final queryset result
self.qs = self.checkbox_filter.qs self.qs = self.checkbox_filter.qs

View File

@ -16,11 +16,11 @@ from django.utils.translation import gettext_lazy as _
from compensation.filters import CompensationTableFilter, EcoAccountTableFilter from compensation.filters import CompensationTableFilter, EcoAccountTableFilter
from compensation.models import Compensation, EcoAccount from compensation.models import Compensation, EcoAccount
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils.tables import BaseTable, TableRenderMixin from konova.utils.tables import BaseTable
import django_tables2 as tables import django_tables2 as tables
class CompensationTable(BaseTable, TableRenderMixin): class CompensationTable(BaseTable):
id = tables.Column( id = tables.Column(
verbose_name=_("Identifier"), verbose_name=_("Identifier"),
orderable=True, orderable=True,
@ -162,7 +162,7 @@ class CompensationTable(BaseTable, TableRenderMixin):
return format_html(html) return format_html(html)
class EcoAccountTable(BaseTable, TableRenderMixin): class EcoAccountTable(BaseTable):
id = tables.Column( id = tables.Column(
verbose_name=_("Identifier"), verbose_name=_("Identifier"),
orderable=True, orderable=True,

View File

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

View File

@ -14,12 +14,12 @@ from django.urls import reverse
import django_tables2 as tables import django_tables2 as tables
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils.tables import BaseTable, TableRenderMixin from konova.utils.tables import BaseTable
from ema.filters import EmaTableFilter from ema.filters import EmaTableFilter
from ema.models import Ema from ema.models import Ema
class EmaTable(BaseTable, TableRenderMixin): class EmaTable(BaseTable):
""" """
Since EMA and compensation are basically the same, we can reuse CompensationTableFilter and extend the EMA filter Since EMA and compensation are basically the same, we can reuse CompensationTableFilter and extend the EMA filter
in the future by inheriting. in the future by inheriting.

View File

@ -5,29 +5,27 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 22.07.21 Created on: 22.07.21
""" """
from konova.filters.table_filters import AbstractTableFilter, SelectionTableFilter, QueryTableFilter, CheckboxTableFilter from konova.filters import QueryTableFilter, CheckboxTableFilter
class InterventionTableFilter(AbstractTableFilter): class InterventionTableFilter:
def __init__(self, user=None, *args, **kwargs): query_filter = None
super().__init__(*args, **kwargs) checkbox_filter = None
self.user = user qs = None
def __init__(self, *args, **kwargs):
user = kwargs.get("user", None)
qs = kwargs.get("queryset", None) qs = kwargs.get("queryset", None)
request_data = kwargs.get("data", None) request_data = kwargs.get("data", None)
# Pipe the queryset through all needed filters self.query_filter = QueryTableFilter(
self.selection_filter = SelectionTableFilter( user=user,
data=request_data, data=request_data,
queryset=qs, queryset=qs,
) )
self.query_filter = QueryTableFilter(
data=request_data,
queryset=self.selection_filter.qs,
)
self.checkbox_filter = CheckboxTableFilter( self.checkbox_filter = CheckboxTableFilter(
user=user, user=user,
data=request_data, data=request_data,
queryset=self.query_filter.qs, queryset=self.query_filter.qs,
) )
self.qs = self.checkbox_filter.qs self.qs = self.checkbox_filter.qs

View File

@ -14,11 +14,11 @@ from django.utils.translation import gettext_lazy as _
from intervention.filters import InterventionTableFilter from intervention.filters import InterventionTableFilter
from intervention.models import Intervention from intervention.models import Intervention
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT, DEFAULT_DATE_FORMAT from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT, DEFAULT_DATE_FORMAT
from konova.utils.tables import BaseTable, TableRenderMixin from konova.utils.tables import BaseTable
import django_tables2 as tables import django_tables2 as tables
class InterventionTable(BaseTable, TableRenderMixin): class InterventionTable(BaseTable):
id = tables.Column( id = tables.Column(
verbose_name=_("Identifier"), verbose_name=_("Identifier"),
orderable=True, orderable=True,

View File

@ -2,21 +2,31 @@
Author: Michel Peltriaux Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 12.01.22 Created on: 11.01.22
""" """
import django_filters import django_filters
from django import forms from django import forms
from django.db.models import QuerySet, Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from dal_select2.widgets import ModelSelect2 from django.contrib.auth.models import User
from django.db.models import QuerySet, Q
from codelist.models import KonovaCode
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID
from intervention.inputs import DummyFilterInput from intervention.inputs import DummyFilterInput
from konova.models import Parcel, District 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): class KeywordTableFilterMixin(django_filters.FilterSet):
q = django_filters.Filter( q = django_filters.Filter(
method='filter_by_keyword', method='filter_by_keyword',
@ -279,10 +289,9 @@ class ShareableTableFilterMixin(django_filters.FilterSet):
abstract = True abstract = True
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.user = kwargs.pop("user", None) super().__init__(*args, **kwargs)
if self.user is None: if self.user is None:
raise AttributeError("User must be set for further filtering!") raise AttributeError("User must be set for further filtering!")
super().__init__(*args, **kwargs)
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 """ Filters queryset depending on value of 'show_all' setting
@ -342,65 +351,18 @@ class RecordableTableFilterMixin(django_filters.FilterSet):
return queryset return queryset
class RegistrationOfficeTableFilterMixin(django_filters.FilterSet): class QueryTableFilter(AbstractTableFilter,
""" A mixin for AbstractTableFilter KeywordTableFilterMixin,
FileNumberTableFilterMixin,
Specialized on filtering for related registration offices GeoReferencedTableFilterMixin):
""" TableFilter holding different filter options for query related filtering
""" """
ro = django_filters.ModelChoiceFilter( pass
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): class CheckboxTableFilter(AbstractTableFilter, ShareableTableFilterMixin, RecordableTableFilterMixin):
""" A mixin for AbstractTableFilter """ TableFilter holding different filter options for checkbox related filtering
Specialized on filtering for related conservation offices
""" """
co = django_filters.ModelChoiceFilter( pass
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

View File

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

View File

@ -1,50 +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 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

View File

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

View File

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

View File

@ -3,16 +3,6 @@
{% load django_tables2 %} {% load django_tables2 %}
{% load i18n static fontawesome_5 %} {% 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 %} {% block body %}
<div class="col-md"> <div class="col-md">
{% if table.title %} {% if table.title %}
@ -92,31 +82,22 @@
</div> </div>
<div id="filter" class="collapse" aria-labelledby="filterHeader"> <div id="filter" class="collapse" aria-labelledby="filterHeader">
<div class="card-body"> <div class="card-body">
<div class=""> <div class="row">
<div class=""> {% with table.filter.query_filter.form as form %}
{% with table.filter.selection_filter.form as form %} {% include 'filter/query_filter.html' %}
{% include 'filter/query_filter.html' %} {% endwith %}
{% endwith %} </div>
</div> <div class="row mt-3">
<hr> {% with table.filter.checkbox_filter.form as form %}
<div class="mt-3"> {% include 'filter/checkbox_filter.html' %}
{% with table.filter.query_filter.form as form %} {% endwith %}
{% include 'filter/query_filter.html' %} </div>
{% endwith %} <hr>
</div> <div class="row mt-3">
<hr> <button class="btn btn-default" title="{% trans 'Filter' %}">
<div class="mt-3"> {% fa5_icon 'filter' %}
{% with table.filter.checkbox_filter.form as form %} {% trans 'Apply filter' %}
{% include 'filter/checkbox_filter.html' %} </button>
{% 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>
</div> </div>