Merge branch 'master' into 138_New_map_client
# Conflicts: # konova/models/geometry.py # konova/urls.py # locale/de/LC_MESSAGES/django.mo # locale/de/LC_MESSAGES/django.po
This commit is contained in:
@@ -118,32 +118,38 @@ class Geometry(BaseResource):
|
||||
_now = timezone.now()
|
||||
underlying_parcels = []
|
||||
for result in fetched_parcels:
|
||||
fetched_parcel = result[typename]
|
||||
parcel_properties = result["properties"]
|
||||
# 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 ", "")
|
||||
flr_val = parcel_properties["flur"].replace("Flur ", "")
|
||||
district = District.objects.get_or_create(
|
||||
key=fetched_parcel["ave:kreisschl"],
|
||||
name=fetched_parcel["ave:kreis"],
|
||||
key=parcel_properties["kreisschl"],
|
||||
name=parcel_properties["kreis"],
|
||||
)[0]
|
||||
municipal = Municipal.objects.get_or_create(
|
||||
key=fetched_parcel["ave:gmdschl"],
|
||||
name=fetched_parcel["ave:gemeinde"],
|
||||
key=parcel_properties["gmdschl"],
|
||||
name=parcel_properties["gemeinde"],
|
||||
district=district,
|
||||
)[0]
|
||||
parcel_group = ParcelGroup.objects.get_or_create(
|
||||
key=fetched_parcel["ave:gemaschl"],
|
||||
name=fetched_parcel["ave:gemarkung"],
|
||||
key=parcel_properties["gemaschl"],
|
||||
name=parcel_properties["gemarkung"],
|
||||
municipal=municipal,
|
||||
)[0]
|
||||
flrstck_nnr = parcel_properties['flstnrnen']
|
||||
if not flrstck_nnr:
|
||||
flrstck_nnr = None
|
||||
flrstck_zhlr = parcel_properties['flstnrzae']
|
||||
if not flrstck_zhlr:
|
||||
flrstck_zhlr = None
|
||||
parcel_obj = Parcel.objects.get_or_create(
|
||||
district=district,
|
||||
municipal=municipal,
|
||||
parcel_group=parcel_group,
|
||||
flr=flr_val,
|
||||
flrstck_nnr=fetched_parcel['ave:flstnrnen'],
|
||||
flrstck_zhlr=fetched_parcel['ave:flstnrzae'],
|
||||
flrstck_nnr=flrstck_nnr,
|
||||
flrstck_zhlr=flrstck_zhlr,
|
||||
)[0]
|
||||
parcel_obj.district = district
|
||||
parcel_obj.updated_on = _now
|
||||
@@ -151,6 +157,7 @@ class Geometry(BaseResource):
|
||||
underlying_parcels.append(parcel_obj)
|
||||
|
||||
# Update the linked parcels
|
||||
self.parcels.clear()
|
||||
self.parcels.set(underlying_parcels)
|
||||
|
||||
# Set the calculated_on intermediate field, so this related data will be found on lookups
|
||||
@@ -171,7 +178,6 @@ class Geometry(BaseResource):
|
||||
Returns:
|
||||
parcels (QuerySet): The related parcels as queryset
|
||||
"""
|
||||
|
||||
parcels = self.parcels.filter(
|
||||
parcelintersection__calculated_on__isnull=False,
|
||||
).prefetch_related(
|
||||
@@ -183,6 +189,17 @@ class Geometry(BaseResource):
|
||||
|
||||
return parcels
|
||||
|
||||
def count_underlying_parcels(self):
|
||||
""" Getter for number of underlying parcels
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
num_parcels = self.parcels.filter(
|
||||
parcelintersection__calculated_on__isnull=False,
|
||||
).count()
|
||||
return num_parcels
|
||||
|
||||
def as_feature_collection(self, srid=DEFAULT_SRID_RLP):
|
||||
""" Returns a FeatureCollection structure holding all polygons of the MultiPolygon as single features
|
||||
|
||||
@@ -211,7 +228,6 @@ class Geometry(BaseResource):
|
||||
return geojson
|
||||
|
||||
|
||||
|
||||
class GeometryConflict(UuidModel):
|
||||
"""
|
||||
Geometry conflicts model
|
||||
|
||||
@@ -652,10 +652,21 @@ class GeoReferencedMixin(models.Model):
|
||||
Returns:
|
||||
parcels (Iterable): An empty list or a Queryset
|
||||
"""
|
||||
result = []
|
||||
if self.geometry is not None:
|
||||
return self.geometry.get_underlying_parcels()
|
||||
else:
|
||||
return []
|
||||
result = self.geometry.get_underlying_parcels()
|
||||
return result
|
||||
|
||||
def count_underlying_parcels(self):
|
||||
""" Getter for number of underlying parcels
|
||||
|
||||
Returns:
|
||||
|
||||
"""
|
||||
result = 0
|
||||
if self.geometry is not None:
|
||||
result = self.geometry.count_underlying_parcels()
|
||||
return result
|
||||
|
||||
def set_geometry_conflict_message(self, request: HttpRequest):
|
||||
if self.geometry is None:
|
||||
|
||||
@@ -262,4 +262,13 @@ Similar to bootstraps 'shadow-lg'
|
||||
padding-left: 2em;
|
||||
}
|
||||
|
||||
*/
|
||||
*/
|
||||
.collapse-icn > i{
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.collapsed .collapse-icn > i{
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
.tree-label.badge{
|
||||
font-size: 90%;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
{% load l10n i18n %}
|
||||
{% for parcel in parcels %}
|
||||
{% if forloop.last and next_page %}
|
||||
<tr hx-get="{% url 'geometry-parcels-content' geom_id next_page %}"
|
||||
hx-trigger="intersect once"
|
||||
hx-swap="afterend">
|
||||
<td>{{parcel.parcel_group.name|default_if_none:"-"}}</td>
|
||||
<td>{{parcel.parcel_group.key|default_if_none:"-"}}</td>
|
||||
<td>{{parcel.flr|default_if_none:"-"|unlocalize}}</td>
|
||||
<td>{{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}}</td>
|
||||
<td>{{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}}</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td>{{parcel.parcel_group.name|default_if_none:"-"}}</td>
|
||||
<td>{{parcel.parcel_group.key|default_if_none:"-"}}</td>
|
||||
<td>{{parcel.flr|default_if_none:"-"|unlocalize}}</td>
|
||||
<td>{{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}}</td>
|
||||
<td>{{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
@@ -5,6 +5,11 @@
|
||||
{% trans 'Parcels can not be calculated, since no geometry is given.' %}
|
||||
</article>
|
||||
{% else %}
|
||||
<div>
|
||||
<h4 class="">
|
||||
<span class="badge rlp-r">{{num_parcels}}</span>
|
||||
{% trans 'Parcels found' %}</h4>
|
||||
</div>
|
||||
<table id="upper-spatial-table" class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -37,16 +42,7 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for parcel in parcels %}
|
||||
<tr>
|
||||
<td>{{parcel.parcel_group.name|default_if_none:"-"}}</td>
|
||||
<td>{{parcel.parcel_group.key|default_if_none:"-"}}</td>
|
||||
<td>{{parcel.flr|default_if_none:"-"|unlocalize}}</td>
|
||||
<td>{{parcel.flrstck_zhlr|default_if_none:"-"|unlocalize}}</td>
|
||||
<td>{{parcel.flrstck_nnr|default_if_none:"-"|unlocalize}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
{% include 'konova/includes/parcels/parcel_table_content.html' %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
@@ -2,18 +2,23 @@
|
||||
|
||||
{% for code in codes %}
|
||||
<div class="ml-4 tree-element">
|
||||
<label class="tree-label" role="{% if not code.is_leaf%}button{% endif %}" for="input_{{code.pk|unlocalize}}" id="{{code.pk|unlocalize}}" data-toggle="collapse" data-target="#children_{{code.pk|unlocalize}}" aria-expanded="true" aria-controls="children_{{code.pk|unlocalize}}">
|
||||
<label class="tree-label collapsed" role="{% if not code.is_leaf%}button{% endif %}" for="input_{{code.pk|unlocalize}}" id="{{code.pk|unlocalize}}" data-toggle="collapse" data-target="#children_{{code.pk|unlocalize}}" aria-expanded="true" aria-controls="children_{{code.pk|unlocalize}}">
|
||||
{% if code.is_leaf%}
|
||||
<input class="tree-input" id="input_{{code.pk|unlocalize}}" name="{{ widget.name }}" type="checkbox" value="{{code.pk|unlocalize}}" {% if code.pk|unlocalize in widget.value %}checked{% endif %}/>
|
||||
{% else %}
|
||||
{% fa5_icon 'angle-right' %}
|
||||
<span class="collapse-icn">
|
||||
{% fa5_icon 'angle-down' %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if code.short_name %}
|
||||
({{code.short_name}})
|
||||
{% endif %}
|
||||
{{code.long_name}}
|
||||
</label>
|
||||
{% if not code.is_leaf %}
|
||||
<div id="children_{{code.pk|unlocalize}}" data-toggle="collapse" class="collapse tree-element-children">
|
||||
{% with code.children as codes %}
|
||||
{% include 'konova/widgets/checkbox-tree-select-content.html' %}
|
||||
{% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -5,7 +5,7 @@
|
||||
</div>
|
||||
|
||||
<div id="tree-root">
|
||||
{% include 'konova/widgets/checkbox-tree-select-content.html' %}
|
||||
{% include 'konova/widgets/tree/checkbox/checkbox-tree-select-content.html' %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -47,9 +47,12 @@
|
||||
}
|
||||
);
|
||||
if(val.length > 0){
|
||||
// Hide everything
|
||||
allTreeElements.hide()
|
||||
// Now show again everything matching the query
|
||||
allTreeElementsContain.show()
|
||||
}else{
|
||||
// Show everything if no query exists
|
||||
allTreeElements.show()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{% load l10n fontawesome_5 %}
|
||||
{% for code in codes %}
|
||||
<div class="ml-4 tree-element">
|
||||
<label class="tree-label collapsed" role="{% if not code.is_leaf%}button{% endif %}" for="input_{{code.pk|unlocalize}}" id="{{code.pk|unlocalize}}" data-toggle="collapse" data-target="#children_{{code.pk|unlocalize}}" aria-expanded="true" aria-controls="children_{{code.pk|unlocalize}}">
|
||||
{% if code.is_leaf%}
|
||||
<input class="tree-input" id="input_{{code.pk|unlocalize}}" name="{{ widget.name }}" type="radio" value="{{code.pk|unlocalize}}" {% if code.pk|unlocalize in widget.value %}checked{% endif %}/>
|
||||
{% else %}
|
||||
<span class="collapse-icn">
|
||||
{% fa5_icon 'angle-down' %}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if code.short_name %}
|
||||
({{code.short_name}})
|
||||
{% endif %}
|
||||
{{code.long_name}}
|
||||
</label>
|
||||
{% if not code.is_leaf %}
|
||||
<div id="children_{{code.pk|unlocalize}}" data-toggle="collapse" class="collapse tree-element-children">
|
||||
{% with code.children as codes %}
|
||||
{% include 'konova/widgets/tree/radio/radio-tree-select-content.html' %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -0,0 +1,62 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div class="ml-4 mb-4">
|
||||
<input id="tree-search-input" class="form-control" type="text" placeholder="{% trans 'Search' %}"/>
|
||||
</div>
|
||||
<div id="tree-root">
|
||||
{% include 'konova/widgets/tree/radio/radio-tree-select-content.html' %}
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSelectedCssClass(element){
|
||||
element = $(element);
|
||||
var cssClass = "badge rlp-r"
|
||||
|
||||
// Find all already tagged input elements and reset them to be untagged
|
||||
var allTaggedInputs = $("#tree-root").find(".badge.rlp-r")
|
||||
allTaggedInputs.removeClass(cssClass)
|
||||
|
||||
// Find all parents of selected element
|
||||
var parentElements = element.parents(".tree-element-children")
|
||||
|
||||
// Tag parents of element
|
||||
var parentLabels = parentElements.siblings(".tree-label");
|
||||
parentLabels.addClass(cssClass);
|
||||
}
|
||||
|
||||
function changeHandler(event){
|
||||
toggleSelectedCssClass(this);
|
||||
}
|
||||
|
||||
function searchInputHandler(event){
|
||||
var elem = $(this);
|
||||
var val = elem.val()
|
||||
var allTreeElements = $(".tree-element")
|
||||
var allTreeElementsContain = $(".tree-element").filter(function(){
|
||||
var reg = new RegExp(val, "i");
|
||||
return reg.test($(this).text());
|
||||
}
|
||||
);
|
||||
if(val.length > 0){
|
||||
// Hide everything
|
||||
allTreeElements.hide()
|
||||
// Now show again everything matching the query
|
||||
allTreeElementsContain.show()
|
||||
}else{
|
||||
// Show everything if no query exists
|
||||
allTreeElements.show()
|
||||
}
|
||||
}
|
||||
|
||||
// Add event listener on search input
|
||||
$("#tree-search-input").keyup(searchInputHandler)
|
||||
|
||||
// Add event listener on changed checkboxes
|
||||
$(".tree-input").change(changeHandler);
|
||||
|
||||
// initialize all pre-checked checkboxes (e.g. on an edit form)
|
||||
var preCheckedElements = $(".tree-input:checked");
|
||||
preCheckedElements.each(function (index, element){
|
||||
toggleSelectedCssClass(element);
|
||||
})
|
||||
</script>
|
||||
@@ -24,7 +24,7 @@ from konova.autocompletes import EcoAccountAutocomplete, \
|
||||
ShareTeamAutocomplete, HandlerCodeAutocomplete
|
||||
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, get_geom_parcels, map_client_proxy_view
|
||||
from konova.views import logout_view, home_view, get_geom_parcels, get_geom_parcels_content, map_client_proxy_view
|
||||
|
||||
sso_client = KonovaSSOClient(SSO_SERVER, SSO_PUBLIC_KEY, SSO_PRIVATE_KEY)
|
||||
urlpatterns = [
|
||||
@@ -40,7 +40,8 @@ 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"),
|
||||
path('geom/<id>/parcels/', get_geom_parcels, name="geometry-parcels"),
|
||||
path('geom/<id>/parcels/<int:page>', get_geom_parcels_content, name="geometry-parcels-content"),
|
||||
path('client/proxy', map_client_proxy_view, name="map-client-proxy"),
|
||||
|
||||
# Autocomplete paths for all apps
|
||||
|
||||
@@ -5,12 +5,13 @@ Contact: michel.peltriaux@sgdnord.rlp.de
|
||||
Created on: 17.12.21
|
||||
|
||||
"""
|
||||
import json
|
||||
from abc import abstractmethod
|
||||
from json import JSONDecodeError
|
||||
from time import sleep
|
||||
|
||||
import requests
|
||||
import xmltodict
|
||||
from django.contrib.gis.db.models.functions import AsGML, Transform
|
||||
from django.contrib.gis.db.models.functions import AsGML, Transform, MakeValid
|
||||
from requests.auth import HTTPDigestAuth
|
||||
|
||||
from konova.settings import DEFAULT_SRID_RLP, PARCEL_WFS_USER, PARCEL_WFS_PW, PROXIES
|
||||
@@ -90,7 +91,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
|
||||
).annotate(
|
||||
transformed=Transform(srid=filter_srid, expression="geom")
|
||||
).annotate(
|
||||
gml=AsGML('transformed')
|
||||
gml=AsGML(MakeValid('transformed'))
|
||||
).first().gml
|
||||
spatial_filter = f"<Filter><{geometry_operation}><PropertyName>{self.geometry_property_name}</PropertyName>{geom_gml}</{geometry_operation}></Filter>"
|
||||
return spatial_filter
|
||||
@@ -115,7 +116,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
|
||||
geometry_operation,
|
||||
filter_srid
|
||||
)
|
||||
_filter = f'<wfs:GetFeature service="WFS" version="{self.version}" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:myns="http://www.someserver.com/myns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0.0/wfs.xsd" count="{self.count}" startindex="{start_index}"><wfs:Query typeNames="{typenames}">{spatial_filter}</wfs:Query></wfs:GetFeature>'
|
||||
_filter = f'<wfs:GetFeature service="WFS" version="{self.version}" xmlns:wfs="http://www.opengis.net/wfs/2.0" xmlns:fes="http://www.opengis.net/fes/2.0" xmlns:myns="http://www.someserver.com/myns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0.0/wfs.xsd" count="{self.count}" startindex="{start_index}" outputFormat="application/json; subtype=geojson"><wfs:Query typeNames="{typenames}">{spatial_filter}</wfs:Query></wfs:GetFeature>'
|
||||
return _filter
|
||||
|
||||
def get_features(self,
|
||||
@@ -139,7 +140,7 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
|
||||
Returns:
|
||||
features (list): A list of returned features
|
||||
"""
|
||||
features = []
|
||||
found_features = []
|
||||
while start_index is not None:
|
||||
post_body = self._create_post_data(
|
||||
spatial_operator,
|
||||
@@ -155,19 +156,11 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
|
||||
)
|
||||
|
||||
content = response.content.decode("utf-8")
|
||||
content = xmltodict.parse(content)
|
||||
collection = content.get(
|
||||
"wfs:FeatureCollection",
|
||||
{},
|
||||
)
|
||||
|
||||
# Check if collection is an exception and does not contain the requested data
|
||||
if len(collection) == 0:
|
||||
exception = content.get(
|
||||
"ows:ExceptionReport",
|
||||
{}
|
||||
)
|
||||
if len(exception) > 0 and rerun_on_exception:
|
||||
try:
|
||||
# Check if collection is an exception and does not contain the requested data
|
||||
content = json.loads(content)
|
||||
except JSONDecodeError as e:
|
||||
if rerun_on_exception:
|
||||
# Wait a second before another try
|
||||
sleep(1)
|
||||
self.get_features(
|
||||
@@ -177,22 +170,21 @@ class ParcelWFSFetcher(AbstractWFSFetcher):
|
||||
start_index,
|
||||
rerun_on_exception=False
|
||||
)
|
||||
|
||||
members = collection.get(
|
||||
"wfs:member",
|
||||
None,
|
||||
)
|
||||
if members is not None:
|
||||
if len(members) > 1:
|
||||
# extend feature list with found list of new feature members
|
||||
features += members
|
||||
else:
|
||||
# convert single found feature member into list and extent feature list
|
||||
features += [members]
|
||||
e.msg += content
|
||||
raise e
|
||||
fetched_features = content.get(
|
||||
"features",
|
||||
{},
|
||||
)
|
||||
|
||||
if collection.get("@next", None) is not None:
|
||||
start_index += self.count
|
||||
else:
|
||||
found_features += fetched_features
|
||||
|
||||
if len(fetched_features) < self.count:
|
||||
# The response was not 'full', so we got everything to fetch
|
||||
start_index = None
|
||||
else:
|
||||
# If a 'full' response returned, there might be more to fetch. Increase the start_index!
|
||||
start_index += self.count
|
||||
|
||||
return features
|
||||
return found_features
|
||||
|
||||
@@ -113,12 +113,12 @@ def get_geom_parcels(request: HttpRequest, id: str):
|
||||
id (str): The geometry's id
|
||||
|
||||
Returns:
|
||||
|
||||
A rendered piece of HTML
|
||||
"""
|
||||
# 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"
|
||||
template = "konova/includes/parcels/parcel_table_frame.html"
|
||||
geom = get_object_or_404(Geometry, id=id)
|
||||
parcels = geom.get_underlying_parcels()
|
||||
geos_geom = geom.geom
|
||||
@@ -136,9 +136,20 @@ def get_geom_parcels(request: HttpRequest, id: str):
|
||||
parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr")
|
||||
municipals = parcels.order_by("municipal").distinct("municipal").values("municipal__id")
|
||||
municipals = Municipal.objects.filter(id__in=municipals)
|
||||
|
||||
rpp = 100
|
||||
num_all_parcels = parcels.count()
|
||||
parcels = parcels[:rpp]
|
||||
next_page = 1
|
||||
if len(parcels) < rpp:
|
||||
next_page = None
|
||||
|
||||
context = {
|
||||
"num_parcels": num_all_parcels,
|
||||
"parcels": parcels,
|
||||
"municipals": municipals,
|
||||
"geom_id": str(id),
|
||||
"next_page": next_page,
|
||||
}
|
||||
html = render_to_string(template, context, request)
|
||||
return HttpResponse(html, status=status_code)
|
||||
@@ -146,6 +157,49 @@ def get_geom_parcels(request: HttpRequest, id: str):
|
||||
return HttpResponse(None, status=404)
|
||||
|
||||
|
||||
@login_required
|
||||
def get_geom_parcels_content(request: HttpRequest, id: str, page: int):
|
||||
""" Getter for infinite scroll of HTMX
|
||||
|
||||
Returns parcels of a specific page/slice of the found parcel set.
|
||||
Implementation of infinite scroll htmx example: https://htmx.org/examples/infinite-scroll/
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The incoming request
|
||||
id (str): The geometry's id
|
||||
page (int): The requested page number
|
||||
|
||||
Returns:
|
||||
A rendered piece of HTML
|
||||
"""
|
||||
if page < 0:
|
||||
raise AssertionError("Parcel page can not be negative")
|
||||
|
||||
# HTTP code 286 states that the HTMX should stop polling for updates
|
||||
# https://htmx.org/docs/#polling
|
||||
status_code = 286
|
||||
template = "konova/includes/parcels/parcel_table_content.html"
|
||||
geom = get_object_or_404(Geometry, id=id)
|
||||
parcels = geom.get_underlying_parcels()
|
||||
|
||||
parcels = parcels.order_by("-municipal", "flr", "flrstck_zhlr", "flrstck_nnr")
|
||||
rpp = 100
|
||||
from_p = rpp * (page-1)
|
||||
to_p = rpp * (page)
|
||||
next_page = page + 1
|
||||
parcels = parcels[from_p:to_p]
|
||||
if len(parcels) < rpp:
|
||||
next_page = None
|
||||
|
||||
context = {
|
||||
"parcels": parcels,
|
||||
"geom_id": str(id),
|
||||
"next_page": next_page,
|
||||
}
|
||||
html = render_to_string(template, context, request)
|
||||
return HttpResponse(html, status=status_code)
|
||||
|
||||
|
||||
def get_404_view(request: HttpRequest, exception=None):
|
||||
""" Returns a 404 handling view
|
||||
|
||||
|
||||
Reference in New Issue
Block a user