#121 Deferred parcels

* improves filtering by gmrkng and krs
* implements deferred loading of parcels on spatial referenced data objects
* adds HTMX to project
* improves detail view layout (mainly interesting for smaller displays/mobile)
This commit is contained in:
2022-02-21 15:18:15 +01:00
parent 9794688f20
commit 0b9587f17c
10 changed files with 178 additions and 186 deletions

View File

@@ -185,7 +185,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
"""
matching_districts = District.objects.filter(
krs=value
krs__icontains=value
)
matching_parcels = Parcel.objects.filter(
district__in=matching_districts
@@ -209,7 +209,7 @@ class GeoReferencedTableFilterMixin(django_filters.FilterSet):
Returns:
"""
queryset = self._filter_parcel_reference(queryset, name, value, "gmrkng__istartswith")
queryset = self._filter_parcel_reference(queryset, name, value, "gmrkng__icontains")
return queryset
def filter_parcel(self, queryset, name, value) -> QuerySet:

View File

@@ -0,0 +1,32 @@
{% load i18n %}
<div class="table-container w-100 scroll-300">
{% if parcels|length == 0 %}
<article class="alert alert-info">
{% trans 'Parcels can not be calculated, since no geometry is given.' %}
</article>
{% else %}
<table class="table table-hover">
<thead>
<tr>
<th scope="col">{% trans 'Kreis' %}</th>
<th scope="col">{% trans 'Gemarkung' %}</th>
<th scope="col">{% trans 'Parcel' %}</th>
<th scope="col">{% trans 'Parcel counter' %}</th>
<th scope="col">{% trans 'Parcel number' %}</th>
</tr>
</thead>
<tbody>
{% for parcel in parcels %}
<tr>
<td>{{parcel.district.krs|default_if_none:"-"}}</td>
<td>{{parcel.gmrkng|default_if_none:"-"}}</td>
<td>{{parcel.flr|default_if_none:"-"}}</td>
<td>{{parcel.flrstck_zhlr|default_if_none:"-"}}</td>
<td>{{parcel.flrstck_nnr|default_if_none:"-"}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>

View File

@@ -1,37 +1,8 @@
{% load i18n %}
<div>
<div class="col-sm-12">
<h3>{% trans 'Spatial reference' %}</h3>
</div>
<div class="table-container w-100 scroll-300">
{% if parcels|length == 0 %}
<article class="alert alert-info">
{% blocktrans %}
If the geometry is not empty, the parcels are currently recalculated. Please refresh this page in a few moments.
{% endblocktrans %}
</article>
{% else %}
<table class="table table-hover">
<thead>
<tr>
<th scope="col">{% trans 'Kreis' %}</th>
<th scope="col">{% trans 'Gemarkung' %}</th>
<th scope="col">{% trans 'Parcel' %}</th>
<th scope="col">{% trans 'Parcel counter' %}</th>
<th scope="col">{% trans 'Parcel number' %}</th>
</tr>
</thead>
<tbody>
{% for parcel in parcels %}
<tr>
<td>{{parcel.district.krs|default_if_none:"-"}}</td>
<td>{{parcel.gmrkng|default_if_none:"-"}}</td>
<td>{{parcel.flr|default_if_none:"-"}}</td>
<td>{{parcel.flrstck_zhlr|default_if_none:"-"}}</td>
<td>{{parcel.flrstck_nnr|default_if_none:"-"}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
<div class="align-middle" hx-trigger="every 2s" hx-get="{% url 'geometry-parcels' geom_form.instance.geometry.id %}">
<span class="spinner-border rlp-r-inv" role="status"></span>
<span>{% trans 'Loading...' %}</span>
</div>
</div>

View File

@@ -23,7 +23,7 @@ from konova.autocompletes import EcoAccountAutocomplete, \
ShareUserAutocomplete, BiotopeExtraCodeAutocomplete, CompensationActionDetailCodeAutocomplete, ShareTeamAutocomplete
from konova.settings import SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY, DEBUG
from konova.sso.sso import KonovaSSOClient
from konova.views import logout_view, home_view
from konova.views import logout_view, home_view, get_geom_parcels
sso_client = KonovaSSOClient(SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY)
urlpatterns = [
@@ -39,6 +39,7 @@ urlpatterns = [
path('cl/', include("codelist.urls")),
path('analysis/', include("analysis.urls")),
path('api/', include("api.urls")),
path('geom/<id>/parcels', get_geom_parcels, name="geometry-parcels"),
# Autocomplete paths for all apps
path("atcmplt/eco-accounts", EcoAccountAutocomplete.as_view(), name="accounts-autocomplete"),

View File

@@ -7,20 +7,17 @@ Created on: 16.11.20
"""
from django.contrib.auth import logout
from django.contrib.auth.decorators import login_required
from django.http import HttpRequest, FileResponse
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect, render, get_object_or_404
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID
from compensation.models import Compensation, EcoAccount
from intervention.models import Intervention
from konova.contexts import BaseContext
from konova.decorators import any_group_check
from konova.forms import RemoveModalForm
from konova.models import Deadline
from konova.models import Deadline, Geometry
from konova.sub_settings.context_settings import TAB_TITLE_IDENTIFIER
from news.models import ServerMessage
from konova.settings import SSO_SERVER_BASE
@@ -102,6 +99,46 @@ def home_view(request: HttpRequest):
return render(request, template, context)
@login_required
def get_geom_parcels(request: HttpRequest, id: str):
""" Getter for HTMX
Returns all parcels of the requested geometry rendered into a simple HTML table
Args:
request (HttpRequest): The incoming request
id (str): The geometry's id
Returns:
"""
# HTTP code 286 states that the HTMX should stop polling for updates
# https://htmx.org/docs/#polling
status_code = 286
template = "konova/includes/parcel_table.html"
geom = get_object_or_404(Geometry, id=id)
parcels = geom.get_underlying_parcels()
geos_geom = geom.geom
parcels_are_currently_calculated = geos_geom is not None and geos_geom.area > 0 and len(parcels) == 0
parcels_available = len(parcels) > 0
no_geometry_given = geos_geom is None
if parcels_are_currently_calculated:
# Parcels are being calculated right now. Change the status code, so polling stays active for fetching
# resutls after the calculation
status_code = 200
if parcels_available or no_geometry_given:
context = {
"parcels": parcels,
}
html = render_to_string(template, context, request)
return HttpResponse(html, status=status_code)
else:
return HttpResponse(None, status=404)
def get_404_view(request: HttpRequest, exception=None):
""" Returns a 404 handling view