Database performance

* optimizes the db fetching for all index views and detail views
* introduces usage of managers.py in all necessary apps for wrapping basic fetch settings
* moves comment.html to comment_card.html under /konova/templates/konova/
* adds/updates translations
* fixes document typos
* drops comment rendering in public reports
* opens public reports in new tabs if button is clicked from the detail view
pull/30/head
mpeltriaux 3 years ago
parent f5f08b979b
commit 85759a636a

@ -0,0 +1,73 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 14.10.21
"""
from django.db import models
class CompensationActionManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"action_type",
"action_type__parent"
)
class CompensationStateManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"biotope_type",
"biotope_type__parent"
)
class CompensationManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"modified",
"intervention",
"intervention__recorded",
"intervention__recorded__user",
"intervention__modified",
"intervention__checked",
"intervention__checked__user",
)
class EcoAccountManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"recorded",
"recorded__user",
"modified",
"modified__user",
).prefetch_related(
"users",
)
class EcoAccountDeductionManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"intervention",
"intervention__recorded",
"created",
)

@ -17,6 +17,8 @@ from django.utils.translation import gettext_lazy as _
from codelist.models import KonovaCode from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, \ from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID, \
CODELIST_COMPENSATION_FUNDING_ID CODELIST_COMPENSATION_FUNDING_ID
from compensation.managers import CompensationStateManager, EcoAccountDeductionManager, CompensationActionManager, \
EcoAccountManager, CompensationManager
from intervention.models import Intervention, ResponsibilityData from intervention.models import Intervention, ResponsibilityData
from konova.models import BaseObject, BaseResource, Geometry, UuidModel, AbstractDocument, \ from konova.models import BaseObject, BaseResource, Geometry, UuidModel, AbstractDocument, \
generate_document_file_upload_path generate_document_file_upload_path
@ -67,6 +69,8 @@ class CompensationState(UuidModel):
) )
surface = models.FloatField() surface = models.FloatField()
objects = CompensationStateManager()
def __str__(self): def __str__(self):
return "{} | {}".format(self.biotope_type, self.surface) return "{} | {}".format(self.biotope_type, self.surface)
@ -102,6 +106,8 @@ class CompensationAction(BaseResource):
unit = models.CharField(max_length=100, null=True, blank=True, choices=UnitChoices.choices) unit = models.CharField(max_length=100, null=True, blank=True, choices=UnitChoices.choices)
comment = models.TextField(blank=True, null=True, help_text="Additional comment") comment = models.TextField(blank=True, null=True, help_text="Additional comment")
objects = CompensationActionManager()
def __str__(self): def __str__(self):
return "{} | {} {}".format(self.action_type, self.amount, self.unit) return "{} | {} {}".format(self.action_type, self.amount, self.unit)
@ -178,6 +184,8 @@ class Compensation(AbstractCompensation):
related_name='compensations' related_name='compensations'
) )
objects = CompensationManager()
def __str__(self): def __str__(self):
return "{}".format(self.identifier) return "{}".format(self.identifier)
@ -301,6 +309,8 @@ class EcoAccount(AbstractCompensation):
default=0, default=0,
) )
objects = EcoAccountManager()
def __str__(self): def __str__(self):
return "{}".format(self.identifier) return "{}".format(self.identifier)
@ -500,5 +510,7 @@ class EcoAccountDeduction(BaseResource):
related_name="deductions", related_name="deductions",
) )
objects = EcoAccountDeductionManager()
def __str__(self): def __str__(self):
return "{} of {}".format(self.surface, self.account) return "{} of {}".format(self.surface, self.account)

@ -148,14 +148,13 @@ class CompensationTable(BaseTable):
Returns: Returns:
""" """
html = ""
if value is None: if value is None:
value = User.objects.none() value = User.objects.none()
has_access = value.filter( has_access = value.filter(
username=self.user.username id=self.user.id
).exists() ).exists()
html += self.render_icn( html = self.render_icn(
tooltip=_("Full access granted") if has_access else _("Access not granted"), tooltip=_("Full access granted") if has_access else _("Access not granted"),
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit", icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",
) )
@ -244,7 +243,7 @@ class EcoAccountTable(BaseTable):
return format_html(html) return format_html(html)
def render_r(self, value, record: EcoAccount): def render_r(self, value, record: EcoAccount):
""" Renders the registered column for an eco account """ Renders the recorded column for an eco account
Args: Args:
value (str): The identifier value value (str): The identifier value
@ -268,7 +267,7 @@ class EcoAccountTable(BaseTable):
return format_html(html) return format_html(html)
def render_e(self, value, record: EcoAccount): def render_e(self, value, record: EcoAccount):
""" Renders the registered column for an eco account """ Renders the editable column for an eco account
Args: Args:
value (str): The identifier value value (str): The identifier value
@ -278,10 +277,9 @@ class EcoAccountTable(BaseTable):
""" """
html = "" html = ""
has_access = value.filter( # Do not use value in here, since value does use unprefetched 'users' manager, where record has already
username=self.user.username # prefetched users data
).exists() has_access = self.user in record.users.all()
html += self.render_icn( html += self.render_icn(
tooltip=_("Full access granted") if has_access else _("Access not granted"), tooltip=_("Full access granted") if has_access else _("Access not granted"),
icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit", icn_class="fas fa-edit rlp-r-inv" if has_access else "far fa-edit",

@ -6,7 +6,7 @@
LANIS LANIS
</button> </button>
</a> </a>
<a href="{% url 'compensation:report' obj.id %}" class="mr-2"> <a href="{% url 'compensation:report' obj.id %}" target="_blank" class="mr-2">
<button class="btn btn-default" title="{% trans 'Public report' %}"> <button class="btn btn-default" title="{% trans 'Public report' %}">
{% fa5_icon 'file-alt' %} {% fa5_icon 'file-alt' %}
</button> </button>

@ -103,7 +103,7 @@
{% include 'map/geom_form.html' %} {% include 'map/geom_form.html' %}
</div> </div>
<div class="row"> <div class="row">
{% include 'compensation/detail/compensation/includes/comment.html' %} {% include 'konova/comment_card.html' %}
</div> </div>
</div> </div>
</div> </div>

@ -4,7 +4,7 @@
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
<h5> <h5>
<span class="badge badge-light">{{obj.actions.count}}</span> <span class="badge badge-light">{{actions.count}}</span>
{% trans 'Actions' context 'Compensation' %} {% trans 'Actions' context 'Compensation' %}
</h5> </h5>
</div> </div>
@ -33,13 +33,15 @@
<th scope="col"> <th scope="col">
{% trans 'Comment' %} {% trans 'Comment' %}
</th> </th>
<th scope="col"> {% if default_member and has_access %}
{% trans 'Action' %} <th scope="col">
</th> {% trans 'Action' %}
</th>
{% endif %}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{% for action in obj.actions.all %} {% for action in actions %}
<tr> <tr>
<td class="align-middle"> <td class="align-middle">
{{ action.action_type }} {{ action.action_type }}

@ -1,23 +0,0 @@
{% load i18n fontawesome_5 %}
{% if obj.comment %}
<div class="w-100">
<div class="card mt-3">
<div class="card-header rlp-gd">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<h5 class="card-title">
{% fa5_icon 'info-circle' %}
{% trans 'Comment' %}
</h5>
</div>
</div>
</div>
<div class="card-body">
<div class="card-text font-italic">
{{obj.comment}}
</div>
</div>
</div>
</div>
{% endif %}

@ -6,7 +6,7 @@
LANIS LANIS
</button> </button>
</a> </a>
<a href="{% url 'compensation:acc-report' obj.id %}" class="mr-2"> <a href="{% url 'compensation:acc-report' obj.id %}" target="_blank" class="mr-2">
<button class="btn btn-default" title="{% trans 'Public report' %}"> <button class="btn btn-default" title="{% trans 'Public report' %}">
{% fa5_icon 'file-alt' %} {% fa5_icon 'file-alt' %}
</button> </button>

@ -51,9 +51,9 @@
</td> </td>
<td class="align-middle"> <td class="align-middle">
{% if deduction.intervention.recorded %} {% if deduction.intervention.recorded %}
<em title='{{ deduction.intervention.recorded_tooltip }}' class='fas fa-bookmark registered-bookmark'></em> <em title="{% trans 'Recorded on' %} {{obj.recorded.timestamp}} {% trans 'by' %} {{obj.recorded.user}}" class='fas fa-bookmark registered-bookmark'></em>
{% else %} {% else %}
<em title='{{ deduction.intervention.recorded_tooltip }}' class='far fa-bookmark'></em> <em title="{% trans 'Not recorded yet' %}" class='far fa-bookmark'></em>
{% endif %} {% endif %}
</td> </td>
<td class="align-middle">{{ deduction.surface|floatformat:2|intcomma }} m²</td> <td class="align-middle">{{ deduction.surface|floatformat:2|intcomma }} m²</td>

@ -4,7 +4,7 @@
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
<h5> <h5>
<span class="badge badge-light">{{obj.after_states.count}}</span> <span class="badge badge-light">{{after_states.count}}</span>
{% trans 'States after' %} {% trans 'States after' %}
</h5> </h5>
</div> </div>
@ -35,9 +35,11 @@
<th scope="col"> <th scope="col">
{% trans 'Surface' %} {% trans 'Surface' %}
</th> </th>
{% if is_default_member and has_access %}
<th scope="col"> <th scope="col">
{% trans 'Action' %} {% trans 'Action' %}
</th> </th>
{% endif %}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

@ -4,7 +4,7 @@
<div class="row"> <div class="row">
<div class="col-sm-6"> <div class="col-sm-6">
<h5> <h5>
<span class="badge badge-light">{{obj.before_states.count}}</span> <span class="badge badge-light">{{before_states.count}}</span>
{% trans 'States before' %} {% trans 'States before' %}
</h5> </h5>
</div> </div>
@ -35,9 +35,11 @@
<th scope="col"> <th scope="col">
{% trans 'Surface' %} {% trans 'Surface' %}
</th> </th>
{% if is_default_member and has_access %}
<th scope="col"> <th scope="col">
{% trans 'Action' %} {% trans 'Action' %}
</th> </th>
{% endif %}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

@ -102,7 +102,7 @@
{% include 'map/geom_form.html' %} {% include 'map/geom_form.html' %}
</div> </div>
<div class="row"> <div class="row">
{% include 'compensation/detail/compensation/includes/comment.html' %} {% include 'konova/comment_card.html' %}
</div> </div>
</div> </div>
</div> </div>

@ -50,9 +50,6 @@
<div class="row"> <div class="row">
{% include 'map/geom_form.html' %} {% include 'map/geom_form.html' %}
</div> </div>
<div class="row">
{% include 'intervention/detail/includes/comment.html' %}
</div>
<div class="row"> <div class="row">
<div class="col-sm-6 col-md-6 col-lg-6"> <div class="col-sm-6 col-md-6 col-lg-6">
<h4>{% trans 'Open in browser' %}</h4> <h4>{% trans 'Open in browser' %}</h4>

@ -0,0 +1,84 @@
{% extends 'public_base.html' %}
{% load i18n fontawesome_5 humanize %}
{% block body %}
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-6">
<h3>{% trans 'Report' %}</h3>
<h4>{{obj.identifier}}</h4>
<div class="table-container">
<table class="table table-hover">
<tr>
<th class="w-25" scope="row">{% trans 'Title' %}</th>
<td class="align-middle">{{obj.title|default_if_none:""}}</td>
</tr>
<tr>
<th scope="row">{% trans 'Conservation office' %}</th>
<td class="align-middle">{{obj.responsible.conservation_office.str_as_office|default_if_none:""}}</td>
</tr>
<tr>
<th scope="row">{% trans 'Conservation office file number' %}</th>
<td class="align-middle">{{obj.responsible.conservation_file_number|default_if_none:""}}</td>
</tr>
<tr>
<th scope="row">{% trans 'Action handler' %}</th>
<td class="align-middle">{{obj.responsible.handler|default_if_none:""}}</td>
</tr>
<tr>
<th scope="row">{% trans 'Funded by' %}</th>
<td class="align-middle">
{% with obj.fundings.all as fundings %}
{% for funding in fundings %}
<div class="badge pill-badge rlp-r-outline">{{funding.short_name}}</div>
<br>
{% empty %}
{% trans 'None' %}
{% endfor %}
{% endwith %}
</td>
</tr>
<tr>
<th scope="row">{% trans 'Deductions for' %}</th>
<td class="align-middle">
{% for deduction in deductions %}
<a href="{% url 'intervention:report' deduction.intervention__id %}">
{{deduction.intervention__identifier}}
</a>
<br>
{% empty %}
{% trans 'None' %}
{% endfor %}
</td>
</tr>
<tr>
<th scope="row">{% trans 'Last modified' %}</th>
<td class="align-middle">
{{obj.modified.timestamp|default_if_none:""|naturalday}}
</td>
</tr>
</table>
</div>
{% include 'compensation/detail/compensation/includes/states-before.html' %}
{% include 'compensation/detail/compensation/includes/states-after.html' %}
{% include 'compensation/detail/compensation/includes/actions.html' %}
</div>
<div class="col-sm-12 col-md-12 col-lg-6">
<div class="row">
{% include 'map/geom_form.html' %}
</div>
<div class="row">
<div class="col-sm-6 col-md-6 col-lg-6">
<h4>{% trans 'Open in browser' %}</h4>
{{ qrcode|safe }}
</div>
<div class="col-sm-6 col-md-6 col-lg-6">
<h4>{% trans 'View in LANIS' %}</h4>
{{ qrcode_lanis|safe }}
</div>
</div>
</div>
</div>
{% endblock %}

@ -42,7 +42,6 @@ def index_view(request: HttpRequest):
A rendered view A rendered view
""" """
template = "generic_index.html" template = "generic_index.html"
user = request.user
eco_accounts = EcoAccount.objects.filter( eco_accounts = EcoAccount.objects.filter(
deleted=None, deleted=None,
) )
@ -167,27 +166,36 @@ def detail_view(request: HttpRequest, id: str):
""" """
template = "compensation/detail/eco_account/view.html" template = "compensation/detail/eco_account/view.html"
acc = get_object_or_404(EcoAccount, id=id) acc = get_object_or_404(
EcoAccount.objects.prefetch_related(
"deadlines",
).select_related(
'geometry',
'responsible',
),
id=id
)
geom_form = SimpleGeomForm(instance=acc) geom_form = SimpleGeomForm(instance=acc)
_user = request.user _user = request.user
is_data_shared = acc.is_shared_with(_user) is_data_shared = acc.is_shared_with(_user)
# Order states according to surface # Order states according to surface
before_states = acc.before_states.all().order_by("-surface") before_states = acc.before_states.order_by("-surface")
after_states = acc.after_states.all().order_by("-surface") after_states = acc.after_states.order_by("-surface")
# Precalculate logical errors between before- and after-states # Precalculate logical errors between before- and after-states
# Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling # Sum() returns None in case of no states, so we catch that and replace it with 0 for easier handling
sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0 sum_before_states = before_states.aggregate(Sum("surface"))["surface__sum"] or 0
sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0 sum_after_states = after_states.aggregate(Sum("surface"))["surface__sum"] or 0
diff_states = abs(sum_before_states - sum_after_states) diff_states = abs(sum_before_states - sum_after_states)
# Calculate rest of available surface for deductions # Calculate rest of available surface for deductions
available_total, available_relative = acc.get_available_rest() available_total, available_relative = acc.get_available_rest()
# Prefetch related data to decrease the amount of db connections
deductions = acc.deductions.filter( deductions = acc.deductions.filter(
intervention__deleted=None, intervention__deleted=None,
) )
actions = acc.actions.all()
context = { context = {
"obj": acc, "obj": acc,
@ -205,6 +213,7 @@ def detail_view(request: HttpRequest, id: str):
"is_ets_member": in_group(_user, ETS_GROUP), "is_ets_member": in_group(_user, ETS_GROUP),
"LANIS_LINK": acc.get_LANIS_link(), "LANIS_LINK": acc.get_LANIS_link(),
"deductions": deductions, "deductions": deductions,
"actions": actions,
} }
context = BaseContext(request, context).context context = BaseContext(request, context).context
return render(request, template, context) return render(request, template, context)
@ -446,7 +455,7 @@ def report_view(request:HttpRequest, id: str):
""" """
# Reuse the compensation report template since EcoAccounts are structurally identical # Reuse the compensation report template since EcoAccounts are structurally identical
template = "compensation/report/report.html" template = "compensation/report/eco_account/report.html"
acc = get_object_or_404(EcoAccount, id=id) acc = get_object_or_404(EcoAccount, id=id)
# If intervention is not recorded (yet or currently) we need to render another template without any data # If intervention is not recorded (yet or currently) we need to render another template without any data
@ -454,18 +463,39 @@ def report_view(request:HttpRequest, id: str):
template = "report/unavailable.html" template = "report/unavailable.html"
return render(request, template, {}) return render(request, template, {})
# Prepare data for map viewer
geom_form = SimpleGeomForm(
instance=acc
)
qrcode_img = generate_qr_code( qrcode_img = generate_qr_code(
request.build_absolute_uri(reverse("compensation:acc-report", args=(id,))), request.build_absolute_uri(reverse("ema:report", args=(id,))),
10 10
) )
qrcode_img_lanis = generate_qr_code( qrcode_img_lanis = generate_qr_code(
acc.get_LANIS_link(), acc.get_LANIS_link(),
7 7
) )
# Order states by surface
before_states = acc.before_states.all().order_by("-surface").select_related("biotope_type__parent")
after_states = acc.after_states.all().order_by("-surface").select_related("biotope_type__parent")
actions = acc.actions.all().select_related("action_type__parent")
# Reduce amount of db fetched data to the bare minimum we need in the template (deduction's intervention id and identifier)
deductions = acc.deductions.all()\
.distinct("intervention")\
.select_related("intervention")\
.values_list("intervention__id", "intervention__identifier", named=True)
context = { context = {
"obj": acc, "obj": acc,
"qrcode": qrcode_img, "qrcode": qrcode_img,
"qrcode_lanis": qrcode_img_lanis, "qrcode_lanis": qrcode_img_lanis,
"has_access": False, # disables action buttons during rendering
"before_states": before_states,
"after_states": after_states,
"geom_form": geom_form,
"actions": actions,
"deductions": deductions,
} }
context = BaseContext(request, context).context context = BaseContext(request, context).context
return render(request, template, context) return render(request, template, context)

@ -0,0 +1,21 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 14.10.21
"""
from django.db import models
class EmaManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"modified",
"modified__user",
"recorded",
"recorded__user",
)

@ -5,6 +5,7 @@ from django.db import models
from django.db.models import QuerySet from django.db.models import QuerySet
from compensation.models import AbstractCompensation from compensation.models import AbstractCompensation
from ema.managers import EmaManager
from konova.models import AbstractDocument, generate_document_file_upload_path from konova.models import AbstractDocument, generate_document_file_upload_path
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, EMA_DOC_PATH from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, EMA_DOC_PATH
from user.models import UserActionLogEntry from user.models import UserActionLogEntry
@ -43,6 +44,8 @@ class Ema(AbstractCompensation):
related_name="+" related_name="+"
) )
objects = EmaManager()
def __str__(self): def __str__(self):
return "{}".format(self.identifier) return "{}".format(self.identifier)

@ -49,7 +49,7 @@ class EmaTable(BaseTable):
lm = tables.Column( lm = tables.Column(
verbose_name=_("Last edit"), verbose_name=_("Last edit"),
orderable=True, orderable=True,
accessor="created__timestamp", accessor="modified__timestamp",
) )
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):
@ -122,7 +122,7 @@ class EmaTable(BaseTable):
""" """
html = "" html = ""
has_access = value.filter( has_access = value.filter(
username=self.user.username id=self.user.id
).exists() ).exists()
html += self.render_icn( html += self.render_icn(

@ -6,7 +6,7 @@
LANIS LANIS
</button> </button>
</a> </a>
<a href="{% url 'ema:report' obj.id %}" class="mr-2"> <a href="{% url 'ema:report' obj.id %}" target="_blank" class="mr-2">
<button class="btn btn-default" title="{% trans 'Public report' %}"> <button class="btn btn-default" title="{% trans 'Public report' %}">
{% fa5_icon 'file-alt' %} {% fa5_icon 'file-alt' %}
</button> </button>

@ -54,9 +54,6 @@
<div class="row"> <div class="row">
{% include 'map/geom_form.html' %} {% include 'map/geom_form.html' %}
</div> </div>
<div class="row">
{% include 'intervention/detail/includes/comment.html' %}
</div>
<div class="row"> <div class="row">
<div class="col-sm-6 col-md-6 col-lg-6"> <div class="col-sm-6 col-md-6 col-lg-6">
<h4>{% trans 'Open in browser' %}</h4> <h4>{% trans 'Open in browser' %}</h4>

@ -0,0 +1,48 @@
"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 14.10.21
"""
from django.db import models
class InterventionManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_queryset().select_related(
"recorded",
"recorded__user",
"modified",
"modified__user",
"checked",
"checked__user",
).prefetch_related(
"users",
)
class LegalDataManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_querset().select_related(
"process_type",
).prefetch_related(
"laws"
)
class ResponsibilityDataManager(models.Manager):
""" Holds default db fetch setting for this model type
"""
def get_queryset(self):
return super().get_querset().select_related(
"registration_office",
"conservation_office",
)

@ -10,16 +10,15 @@ import shutil
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.gis.db import models from django.contrib.gis.db import models
from django.db.models import QuerySet from django.db.models import QuerySet
from django.utils.timezone import localtime
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from codelist.models import KonovaCode from codelist.models import KonovaCode
from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_LAW_ID, \ from codelist.settings import CODELIST_REGISTRATION_OFFICE_ID, CODELIST_CONSERVATION_OFFICE_ID, CODELIST_LAW_ID, \
CODELIST_PROCESS_TYPE_ID CODELIST_PROCESS_TYPE_ID
from intervention.managers import InterventionManager, LegalDataManager, ResponsibilityDataManager
from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \ from konova.models import BaseObject, Geometry, UuidModel, BaseResource, AbstractDocument, \
generate_document_file_upload_path generate_document_file_upload_path
from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT from konova.settings import DEFAULT_SRID_RLP, LANIS_LINK_TEMPLATE, LANIS_ZOOM_LUT
from konova.sub_settings.django_settings import DEFAULT_DATE_TIME_FORMAT
from konova.utils import generators from konova.utils import generators
from user.models import UserActionLogEntry from user.models import UserActionLogEntry
@ -57,6 +56,8 @@ class ResponsibilityData(UuidModel):
conservation_file_number = models.CharField(max_length=1000, blank=True, null=True) conservation_file_number = models.CharField(max_length=1000, blank=True, null=True)
handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher' or 'Maßnahmenträger'") handler = models.CharField(max_length=500, null=True, blank=True, help_text="Refers to 'Eingriffsverursacher' or 'Maßnahmenträger'")
objects = ResponsibilityDataManager()
def __str__(self): def __str__(self):
return "ZB: {} | ETS: {} | Handler: {}".format( return "ZB: {} | ETS: {} | Handler: {}".format(
self.registration_office, self.registration_office,
@ -171,6 +172,8 @@ class LegalData(UuidModel):
revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL) revocation = models.OneToOneField(Revocation, null=True, blank=True, help_text="Refers to 'Widerspruch am'", on_delete=models.SET_NULL)
objects = LegalDataManager()
class Intervention(BaseObject): class Intervention(BaseObject):
""" """
@ -221,6 +224,8 @@ class Intervention(BaseObject):
help_text="Used for sharing access", help_text="Used for sharing access",
) )
objects = InterventionManager()
def __str__(self): def __str__(self):
return "{} ({})".format(self.identifier, self.title) return "{} ({})".format(self.identifier, self.title)
@ -379,16 +384,6 @@ class Intervention(BaseObject):
y, y,
) )
@property
def recorded_tooltip(self):
tooltip = _("Not recorded yet")
if self.recorded:
value = self.recorded.timestamp
value = localtime(value)
on = value.strftime(DEFAULT_DATE_TIME_FORMAT)
tooltip = _("Recorded on {} by {}").format(on, self.recorded.user)
return tooltip
def get_documents(self) -> (QuerySet, QuerySet): def get_documents(self) -> (QuerySet, QuerySet):
""" Getter for all documents of an intervention """ Getter for all documents of an intervention

@ -117,7 +117,7 @@ class InterventionTable(BaseTable):
return format_html(html) return format_html(html)
def render_r(self, value, record: Intervention): def render_r(self, value, record: Intervention):
""" Renders the registered column for an intervention """ Renders the recorded column for an intervention
Args: Args:
value (str): The identifier value value (str): The identifier value
@ -141,7 +141,7 @@ class InterventionTable(BaseTable):
return format_html(html) return format_html(html)
def render_e(self, value, record: Intervention): def render_e(self, value, record: Intervention):
""" Renders the registered column for an intervention """ Renders the editable column for an intervention
Args: Args:
value (str): The identifier value value (str): The identifier value
@ -152,7 +152,7 @@ class InterventionTable(BaseTable):
""" """
html = "" html = ""
has_access = value.filter( has_access = value.filter(
username=self.user.username id=self.user.id
).exists() ).exists()
html += self.render_icn( html += self.render_icn(

@ -1,23 +0,0 @@
{% load i18n fontawesome_5 %}
{% if obj.comment %}
<div class="w-100">
<div class="card mt-3">
<div class="card-header rlp-gd">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12">
<h5 class="card-title">
{% fa5_icon 'info-circle' %}
{% trans 'Comment' %}
</h5>
</div>
</div>
</div>
<div class="card-body">
<div class="card-text font-italic">
{{obj.comment}}
</div>
</div>
</div>
</div>
{% endif %}

@ -6,7 +6,7 @@
LANIS LANIS
</button> </button>
</a> </a>
<a href="{% url 'intervention:report' obj.id %}" class="mr-2" target="_blank"> <a href="{% url 'intervention:report' obj.id %}" target="_blank" class="mr-2" target="_blank">
<button class="btn btn-default" title="{% trans 'Public report' %}"> <button class="btn btn-default" title="{% trans 'Public report' %}">
{% fa5_icon 'file-alt' %} {% fa5_icon 'file-alt' %}
</button> </button>

@ -127,7 +127,7 @@
{% include 'map/geom_form.html' %} {% include 'map/geom_form.html' %}
</div> </div>
<div class="row"> <div class="row">
{% include 'intervention/detail/includes/comment.html' %} {% include 'konova/comment_card.html' %}
</div> </div>
</div> </div>
</div> </div>

@ -100,9 +100,6 @@
<div class="row"> <div class="row">
{% include 'map/geom_form.html' %} {% include 'map/geom_form.html' %}
</div> </div>
<div class="row">
{% include 'intervention/detail/includes/comment.html' %}
</div>
<div class="row"> <div class="row">
<div class="col-sm-6 col-md-6 col-lg-6"> <div class="col-sm-6 col-md-6 col-lg-6">
<h4>{% trans 'Open in browser' %}</h4> <h4>{% trans 'Open in browser' %}</h4>

@ -35,6 +35,8 @@ def index_view(request: HttpRequest):
# Filtering by user access is performed in table filter inside of InterventionTableFilter class # Filtering by user access is performed in table filter inside of InterventionTableFilter class
interventions = Intervention.objects.filter( interventions = Intervention.objects.filter(
deleted=None, # not deleted deleted=None, # not deleted
).select_related(
"legal"
) )
table = InterventionTable( table = InterventionTable(
request=request, request=request,
@ -194,7 +196,14 @@ def detail_view(request: HttpRequest, id: str):
template = "intervention/detail/view.html" template = "intervention/detail/view.html"
# Fetch data, filter out deleted related data # Fetch data, filter out deleted related data
intervention = get_object_or_404(Intervention, id=id) intervention = get_object_or_404(
Intervention.objects.select_related(
"geometry",
"legal",
"responsible",
),
id=id
)
compensations = intervention.compensations.filter( compensations = intervention.compensations.filter(
deleted=None, deleted=None,
) )

@ -149,7 +149,7 @@ class BaseObject(BaseResource):
""" """
if hasattr(self, "users"): if hasattr(self, "users"):
return self.users.filter(username=user.username).exists() return self.users.filter(id=user.id)
else: else:
return User.objects.none() return User.objects.none()

@ -1,5 +1,10 @@
{% load i18n fontawesome_5 %} {% load i18n fontawesome_5 %}
{% comment %}
Used in e.g. reports and detail views for every model which supports comment field (BaseObject derived)
{% endcomment %}
{% if obj.comment %} {% if obj.comment %}
<div class="w-100"> <div class="w-100">
<div class="card mt-3"> <div class="card mt-3">

Binary file not shown.

@ -19,7 +19,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-10-14 08:46+0200\n" "POT-Creation-Date: 2021-10-14 09:12+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -51,6 +51,7 @@ msgstr "Automatisch generiert"
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:28 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:28
#: compensation/templates/compensation/detail/eco_account/view.html:31 #: compensation/templates/compensation/detail/eco_account/view.html:31
#: compensation/templates/compensation/report/compensation/report.html:12 #: compensation/templates/compensation/report/compensation/report.html:12
#: compensation/templates/compensation/report/eco_account/report.html:12
#: ema/tables.py:33 ema/templates/ema/detail/includes/documents.html:28 #: ema/tables.py:33 ema/templates/ema/detail/includes/documents.html:28
#: ema/templates/ema/detail/view.html:24 #: ema/templates/ema/detail/view.html:24
#: ema/templates/ema/report/report.html:12 intervention/forms/forms.py:39 #: ema/templates/ema/report/report.html:12 intervention/forms/forms.py:39
@ -89,22 +90,19 @@ msgstr "Auswählen..."
#: compensation/forms/forms.py:73 compensation/forms/modalForms.py:61 #: compensation/forms/forms.py:73 compensation/forms/modalForms.py:61
#: compensation/forms/modalForms.py:272 compensation/forms/modalForms.py:367 #: compensation/forms/modalForms.py:272 compensation/forms/modalForms.py:367
#: compensation/templates/compensation/detail/compensation/includes/actions.html:34 #: compensation/templates/compensation/detail/compensation/includes/actions.html:34
#: compensation/templates/compensation/detail/compensation/includes/comment.html:11
#: compensation/templates/compensation/detail/compensation/includes/deadlines.html:34 #: compensation/templates/compensation/detail/compensation/includes/deadlines.html:34
#: compensation/templates/compensation/detail/compensation/includes/documents.html:31 #: compensation/templates/compensation/detail/compensation/includes/documents.html:31
#: compensation/templates/compensation/detail/eco_account/includes/actions.html:34 #: compensation/templates/compensation/detail/eco_account/includes/actions.html:34
#: compensation/templates/compensation/detail/eco_account/includes/comment.html:11
#: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:34 #: compensation/templates/compensation/detail/eco_account/includes/deadlines.html:34
#: compensation/templates/compensation/detail/eco_account/includes/documents.html:31 #: compensation/templates/compensation/detail/eco_account/includes/documents.html:31
#: ema/templates/ema/detail/includes/actions.html:34 #: ema/templates/ema/detail/includes/actions.html:34
#: ema/templates/ema/detail/includes/deadlines.html:34 #: ema/templates/ema/detail/includes/deadlines.html:34
#: ema/templates/ema/detail/includes/documents.html:31 #: ema/templates/ema/detail/includes/documents.html:31
#: intervention/forms/forms.py:179 intervention/forms/modalForms.py:132 #: intervention/forms/forms.py:179 intervention/forms/modalForms.py:132
#: intervention/templates/intervention/detail/includes/comment.html:11
#: intervention/templates/intervention/detail/includes/documents.html:31 #: intervention/templates/intervention/detail/includes/documents.html:31
#: intervention/templates/intervention/detail/includes/payments.html:34 #: intervention/templates/intervention/detail/includes/payments.html:34
#: intervention/templates/intervention/detail/includes/revocation.html:38 #: intervention/templates/intervention/detail/includes/revocation.html:38
#: konova/forms.py:371 #: konova/forms.py:371 konova/templates/konova/comment_card.html:16
msgid "Comment" msgid "Comment"
msgstr "Kommentar" msgstr "Kommentar"
@ -114,8 +112,9 @@ msgstr "Zusätzlicher Kommentar"
#: compensation/forms/forms.py:93 #: compensation/forms/forms.py:93
#: compensation/templates/compensation/detail/eco_account/view.html:58 #: compensation/templates/compensation/detail/eco_account/view.html:58
#: compensation/templates/compensation/report/eco_account/report.html:16
#: ema/templates/ema/detail/view.html:42 #: ema/templates/ema/detail/view.html:42
#: ema/templates/ema/report/report.html:29 intervention/forms/forms.py:101 #: ema/templates/ema/report/report.html:16 intervention/forms/forms.py:101
#: intervention/templates/intervention/detail/view.html:56 #: intervention/templates/intervention/detail/view.html:56
#: intervention/templates/intervention/report/report.html:37 #: intervention/templates/intervention/report/report.html:37
msgid "Conservation office" msgid "Conservation office"
@ -127,8 +126,9 @@ msgstr "Verantwortliche Stelle"
#: compensation/forms/forms.py:109 #: compensation/forms/forms.py:109
#: compensation/templates/compensation/detail/eco_account/view.html:62 #: compensation/templates/compensation/detail/eco_account/view.html:62
#: compensation/templates/compensation/report/eco_account/report.html:20
#: ema/templates/ema/detail/view.html:46 #: ema/templates/ema/detail/view.html:46
#: ema/templates/ema/report/report.html:33 intervention/forms/forms.py:129 #: ema/templates/ema/report/report.html:20 intervention/forms/forms.py:129
#: intervention/templates/intervention/detail/view.html:60 #: intervention/templates/intervention/detail/view.html:60
#: intervention/templates/intervention/report/report.html:41 #: intervention/templates/intervention/report/report.html:41
msgid "Conservation office file number" msgid "Conservation office file number"
@ -687,16 +687,19 @@ msgstr "Verzeichnet am"
#: compensation/templates/compensation/detail/compensation/view.html:71 #: compensation/templates/compensation/detail/compensation/view.html:71
#: compensation/templates/compensation/detail/eco_account/view.html:70 #: compensation/templates/compensation/detail/eco_account/view.html:70
#: compensation/templates/compensation/report/compensation/report.html:24 #: compensation/templates/compensation/report/compensation/report.html:24
#: compensation/templates/compensation/report/eco_account/report.html:28
#: ema/templates/ema/detail/view.html:54 #: ema/templates/ema/detail/view.html:54
#: ema/templates/ema/report/report.html:16 #: ema/templates/ema/report/report.html:28
msgid "Funded by" msgid "Funded by"
msgstr "Gefördert mit" msgstr "Gefördert mit"
#: compensation/templates/compensation/detail/compensation/view.html:79 #: compensation/templates/compensation/detail/compensation/view.html:79
#: compensation/templates/compensation/detail/eco_account/view.html:78 #: compensation/templates/compensation/detail/eco_account/view.html:78
#: compensation/templates/compensation/report/compensation/report.html:31 #: compensation/templates/compensation/report/compensation/report.html:31
#: compensation/templates/compensation/report/eco_account/report.html:35
#: compensation/templates/compensation/report/eco_account/report.html:49
#: ema/templates/ema/detail/view.html:62 #: ema/templates/ema/detail/view.html:62
#: ema/templates/ema/report/report.html:23 #: ema/templates/ema/report/report.html:35
#: intervention/templates/intervention/report/report.html:57 #: intervention/templates/intervention/report/report.html:57
#: intervention/templates/intervention/report/report.html:78 #: intervention/templates/intervention/report/report.html:78
msgid "None" msgid "None"
@ -705,6 +708,7 @@ msgstr ""
#: compensation/templates/compensation/detail/compensation/view.html:84 #: compensation/templates/compensation/detail/compensation/view.html:84
#: compensation/templates/compensation/detail/eco_account/view.html:83 #: compensation/templates/compensation/detail/eco_account/view.html:83
#: compensation/templates/compensation/report/compensation/report.html:37 #: compensation/templates/compensation/report/compensation/report.html:37
#: compensation/templates/compensation/report/eco_account/report.html:54
#: ema/templates/ema/detail/view.html:67 #: ema/templates/ema/detail/view.html:67
#: ema/templates/ema/report/report.html:41 #: ema/templates/ema/report/report.html:41
#: intervention/templates/intervention/detail/view.html:108 #: intervention/templates/intervention/detail/view.html:108
@ -779,27 +783,37 @@ msgid "Missing"
msgstr "Fehlt" msgstr "Fehlt"
#: compensation/templates/compensation/detail/eco_account/view.html:66 #: compensation/templates/compensation/detail/eco_account/view.html:66
#: compensation/templates/compensation/report/eco_account/report.html:24
#: ema/templates/ema/detail/view.html:50
#: ema/templates/ema/report/report.html:24
msgid "Action handler" msgid "Action handler"
msgstr "Maßnahmenträger" msgstr "Maßnahmenträger"
#: compensation/templates/compensation/report/compensation/report.html:7 #: compensation/templates/compensation/report/compensation/report.html:7
#: compensation/templates/compensation/report/eco_account/report.html:7
#: ema/templates/ema/report/report.html:7 #: ema/templates/ema/report/report.html:7
#: intervention/templates/intervention/report/report.html:7 #: intervention/templates/intervention/report/report.html:7
msgid "Report" msgid "Report"
msgstr "Bericht" msgstr "Bericht"
#: compensation/templates/compensation/report/compensation/report.html:58 #: compensation/templates/compensation/report/compensation/report.html:58
#: compensation/templates/compensation/report/eco_account/report.html:75
#: ema/templates/ema/report/report.html:62 #: ema/templates/ema/report/report.html:62
#: intervention/templates/intervention/report/report.html:108 #: intervention/templates/intervention/report/report.html:108
msgid "Open in browser" msgid "Open in browser"
msgstr "Im Browser öffnen" msgstr "Im Browser öffnen"
#: compensation/templates/compensation/report/compensation/report.html:62 #: compensation/templates/compensation/report/compensation/report.html:62
#: compensation/templates/compensation/report/eco_account/report.html:79
#: ema/templates/ema/report/report.html:66 #: ema/templates/ema/report/report.html:66
#: intervention/templates/intervention/report/report.html:112 #: intervention/templates/intervention/report/report.html:112
msgid "View in LANIS" msgid "View in LANIS"
msgstr "In LANIS öffnen" msgstr "In LANIS öffnen"
#: compensation/templates/compensation/report/eco_account/report.html:41
msgid "Deductions for"
msgstr "Abbuchungen für"
#: compensation/views/compensation_views.py:77 #: compensation/views/compensation_views.py:77
msgid "Compensation {} added" msgid "Compensation {} added"
msgstr "Kompensation {} hinzugefügt" msgstr "Kompensation {} hinzugefügt"
@ -913,13 +927,6 @@ msgstr ""
msgid "Payment funded compensation" msgid "Payment funded compensation"
msgstr "Ersatzzahlungsmaßnahme" msgstr "Ersatzzahlungsmaßnahme"
#: ema/templates/ema/detail/view.html:50
#: ema/templates/ema/report/report.html:37 intervention/forms/forms.py:141
#: intervention/templates/intervention/detail/view.html:64
#: intervention/templates/intervention/report/report.html:45
msgid "Intervention handler"
msgstr "Eingriffsverursacher"
#: ema/views.py:78 #: ema/views.py:78
msgid "EMA {} added" msgid "EMA {} added"
msgstr "EMA {} hinzugefügt" msgstr "EMA {} hinzugefügt"
@ -984,6 +991,12 @@ msgstr "Aktenzeichen Zulassungsbehörde"
msgid "ZB-123/ABC.456" msgid "ZB-123/ABC.456"
msgstr "" msgstr ""
#: intervention/forms/forms.py:141
#: intervention/templates/intervention/detail/view.html:64
#: intervention/templates/intervention/report/report.html:45
msgid "Intervention handler"
msgstr "Eingriffsverursacher"
#: intervention/forms/forms.py:145 #: intervention/forms/forms.py:145
msgid "Who performs the intervention" msgid "Who performs the intervention"
msgstr "Wer führt den Eingriff durch" msgstr "Wer führt den Eingriff durch"

Loading…
Cancel
Save