From 4647be958b32458e94c723439ed285d960636a7e Mon Sep 17 00:00:00 2001 From: mipel Date: Thu, 29 Jul 2021 15:49:19 +0200 Subject: [PATCH 1/4] Intervention model refactoring * adds UserActionLogEntry model to user/models.py * wraps user and timestamp info * can be extended for more information in the future * refactors all filtering and accessing on values --- compensation/filters.py | 2 +- compensation/tables.py | 12 ++++---- intervention/filters.py | 2 +- intervention/models.py | 29 ++++++++++++------- intervention/tables.py | 10 ++++--- .../templates/intervention/detail/view.html | 4 +-- konova/enums.py | 8 +++++ user/admin.py | 12 +++++++- user/models.py | 27 +++++++++++++++++ 9 files changed, 82 insertions(+), 24 deletions(-) diff --git a/compensation/filters.py b/compensation/filters.py index 75d6085a..9d0f3b32 100644 --- a/compensation/filters.py +++ b/compensation/filters.py @@ -31,7 +31,7 @@ class CompensationTableFilter(InterventionTableFilter): """ if not value: return queryset.filter( - intervention__recorded_on=None, + intervention__recorded=None, ) else: return queryset diff --git a/compensation/tables.py b/compensation/tables.py index d187338f..0277b52b 100644 --- a/compensation/tables.py +++ b/compensation/tables.py @@ -34,13 +34,13 @@ class CompensationTable(BaseTable): verbose_name=_("Checked"), orderable=True, empty_values=[], - accessor="intervention__checked_on", + accessor="intervention__checked", ) r = tables.Column( verbose_name=_("Recorded"), orderable=True, empty_values=[], - accessor="intervention__recorded_on", + accessor="intervention__recorded", ) e = tables.Column( verbose_name=_("Editable"), @@ -90,7 +90,7 @@ class CompensationTable(BaseTable): def render_c(self, value, record: Compensation): """ Renders the checked column for a compensation - checked_on is set by the main object Intervention + checked is set by the main object Intervention Args: value (str): The identifier value @@ -103,9 +103,10 @@ class CompensationTable(BaseTable): checked = value is not None tooltip = _("Not checked yet") if checked: + value = value.timestamp value = localtime(value) checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Checked on {} by {}").format(checked_on, record.intervention.checked_by) + tooltip = _("Checked on {} by {}").format(checked_on, record.intervention.checked.user) html += self.render_checked_star( tooltip=tooltip, icn_filled=checked, @@ -126,9 +127,10 @@ class CompensationTable(BaseTable): checked = value is not None tooltip = _("Not registered yet") if checked: + value = value.timestamp value = localtime(value) on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Registered on {} by {}").format(on, record.intervention.recorded_by) + tooltip = _("Registered on {} by {}").format(on, record.intervention.recorded.user) html += self.render_bookmark( tooltip=tooltip, icn_filled=checked, diff --git a/intervention/filters.py b/intervention/filters.py index 7eb9553f..319a0992 100644 --- a/intervention/filters.py +++ b/intervention/filters.py @@ -117,7 +117,7 @@ class InterventionTableFilter(django_filters.FilterSet): """ if not value: return queryset.filter( - recorded_on=None, + recorded=None, ) else: return queryset diff --git a/intervention/models.py b/intervention/models.py index 6d72078e..5280c840 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -15,6 +15,7 @@ from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_I from konova.models import BaseObject, Geometry from konova.utils.generators import generate_random_string from organisation.models import Organisation +from user.models import UserActionLogEntry class Intervention(BaseObject): @@ -32,27 +33,35 @@ class Intervention(BaseObject): geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) - # Checks - checked_on = models.DateTimeField(default=None, null=True, blank=True) - checked_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') - # Refers to "zugelassen am" registration_date = models.DateField(null=True, blank=True) # Refers to "Bestandskraft am" binding_on = models.DateField(null=True, blank=True) + # Checks - Refers to "Genehmigen" but optional + checked = models.OneToOneField( + UserActionLogEntry, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Holds data on user and timestamp of this action", + related_name="+" + ) + # Refers to "verzeichnen" - recorded_on = models.DateTimeField(default=None, null=True, blank=True) - recorded_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL, related_name='+') + recorded = models.OneToOneField( + UserActionLogEntry, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Holds data on user and timestamp of this action", + related_name="+" + ) # Holds which intervention is simply a newer version of this dataset next_version = models.ForeignKey("Intervention", null=True, blank=True, on_delete=models.DO_NOTHING) - # Compensation or payments, one-directional - #payments = models.ManyToManyField(Payment, related_name="+", blank=True) - #compensations = models.ManyToManyField(Compensation, related_name="+", blank=True) - # Users having access on this object users = models.ManyToManyField(User) diff --git a/intervention/tables.py b/intervention/tables.py index 69d93b85..570eed41 100644 --- a/intervention/tables.py +++ b/intervention/tables.py @@ -33,13 +33,13 @@ class InterventionTable(BaseTable): verbose_name=_("Checked"), orderable=True, empty_values=[], - accessor="checked_on", + accessor="checked", ) r = tables.Column( verbose_name=_("Recorded"), orderable=True, empty_values=[], - accessor="recorded_on", + accessor="recorded", ) e = tables.Column( verbose_name=_("Editable"), @@ -110,9 +110,10 @@ class InterventionTable(BaseTable): checked = value is not None tooltip = _("Not checked yet") if checked: + value = value.timestamp value = localtime(value) checked_on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Checked on {} by {}").format(checked_on, record.checked_by) + tooltip = _("Checked on {} by {}").format(checked_on, record.checked.user) html += self.render_checked_star( tooltip=tooltip, icn_filled=checked, @@ -133,9 +134,10 @@ class InterventionTable(BaseTable): checked = value is not None tooltip = _("Not registered yet") if checked: + value = value.timestamp value = localtime(value) on = value.strftime(DEFAULT_DATE_TIME_FORMAT) - tooltip = _("Registered on {} by {}").format(on, record.recorded_by) + tooltip = _("Registered on {} by {}").format(on, record.recorded.user) html += self.render_bookmark( tooltip=tooltip, icn_filled=checked, diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index 9cddd4a5..e19d3c16 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -93,7 +93,7 @@ {% trans 'Checked' %} - {% if intervention.checked_on is None %} + {% if intervention.checked is None %} {% fa5_icon 'star' 'far' %} @@ -107,7 +107,7 @@ {% trans 'Recorded' %} - {% if intervention.recorded_on is None %} + {% if intervention.recorded is None %} {% fa5_icon 'bookmark' 'far' %} diff --git a/konova/enums.py b/konova/enums.py index cabb9788..1f54cf9a 100644 --- a/konova/enums.py +++ b/konova/enums.py @@ -47,3 +47,11 @@ class ServerMessageImportance(BaseEnum): DEFAULT = "DEFAULT" INFO = "INFO" WARNING = "WARNING" + + +class UserActionLogEntryEnum(BaseEnum): + """ + Defines different possible user actions for UserActionLogEntry + """ + CHECKED = "Checked" + RECORDED = "Recorded" diff --git a/user/admin.py b/user/admin.py index fb8a5d68..9a633e77 100644 --- a/user/admin.py +++ b/user/admin.py @@ -1,6 +1,6 @@ from django.contrib import admin -from user.models import UserNotification, KonovaUserExtension +from user.models import UserNotification, KonovaUserExtension, UserActionLogEntry class UserNotificationAdmin(admin.ModelAdmin): @@ -17,5 +17,15 @@ class KonovaUserExtensionAdmin(admin.ModelAdmin): ] +class UserActionLogEntryAdmin(admin.ModelAdmin): + list_display = [ + "id", + "user", + "timestamp", + "action", + ] + + admin.site.register(UserNotification, UserNotificationAdmin) admin.site.register(KonovaUserExtension, KonovaUserExtensionAdmin) +admin.site.register(UserActionLogEntry, UserActionLogEntryAdmin) \ No newline at end of file diff --git a/user/models.py b/user/models.py index 428b4f5b..588bf2f1 100644 --- a/user/models.py +++ b/user/models.py @@ -1,6 +1,9 @@ +import uuid + from django.contrib.auth.models import User from django.db import models +from konova.enums import UserActionLogEntryEnum from user.enums import UserNotificationEnum @@ -36,3 +39,27 @@ class KonovaUserExtension(models.Model): """ user = models.OneToOneField(User, on_delete=models.CASCADE) notifications = models.ManyToManyField(UserNotification, related_name="+") + + +class UserActionLogEntry(models.Model): + """ Wraps a user action log entry + + Can be used for workflow related attributes like checking or recording. + + """ + id = models.UUIDField( + primary_key=True, + default=uuid.uuid4, + ) + user = models.ForeignKey(User, related_name='+', on_delete=models.CASCADE, help_text="Performing user") + timestamp = models.DateTimeField(auto_now_add=True, help_text="Timestamp of performed action") + action = models.CharField( + max_length=255, + null=True, + blank=True, + help_text="Short name for performed action - optional", + choices=UserActionLogEntryEnum.as_choices(drop_empty_choice=True), + ) + + def __str__(self): + return "{} | {} | {}".format(self.user.username, self.timestamp, self.action) \ No newline at end of file From 5858a5fdf99794b9fc7895176b0c864becd2f612 Mon Sep 17 00:00:00 2001 From: mipel Date: Thu, 29 Jul 2021 16:10:56 +0200 Subject: [PATCH 2/4] Compensation users refactoring * moves accessibility of compensations completely into related intervention.users set * this way the visibility for a compensation can not differ from the one of the 'parent' intervention --- compensation/filters.py | 18 ++++++++++++++++++ compensation/models.py | 6 +++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/compensation/filters.py b/compensation/filters.py index 9d0f3b32..ab7a5fe7 100644 --- a/compensation/filters.py +++ b/compensation/filters.py @@ -18,6 +18,24 @@ class CompensationTableFilter(InterventionTableFilter): """ + def _filter_show_all(self, queryset, name, value) -> QuerySet: + """ Filters queryset depending on value of 'show_all' setting + + Args: + queryset (): + name (): + value (): + + Returns: + + """ + if not value: + return queryset.filter( + intervention__users__in=[self.user], # requesting user has access + ) + else: + return queryset + def _filter_show_recorded(self, queryset, name, value) -> QuerySet: """ Filters queryset depending on value of 'show_recorded' setting diff --git a/compensation/models.py b/compensation/models.py index d7625d1e..f83e598e 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -100,9 +100,6 @@ class Compensation(BaseObject): related_name='compensations' ) - # Users having access on this object - users = models.ManyToManyField(User) - @staticmethod def _generate_new_identifier() -> str: """ Generates a new identifier for the intervention object @@ -153,3 +150,6 @@ class EcoAccount(Compensation): with some kind of currency. From this account one is able to 'withdraw' currency for current projects. """ handler = models.CharField(max_length=500, null=True, blank=True, help_text="Who is responsible for handling the actions") + + # Users having access on this object + users = models.ManyToManyField(User) From e327f03893aaa9966effba0821537ced793e211f Mon Sep 17 00:00:00 2001 From: mipel Date: Fri, 30 Jul 2021 09:30:33 +0200 Subject: [PATCH 3/4] Intervention model refactoring * splits Intervention model into three main components * Intervention (main object) * LegalData (holds legal dates, laws, etc.) * ResponsibilityData (holds organizations and handler) * This way data can be extended more easily in the future * refactors admin.py and usages in templates * introduces UuidModel as a base class for BaseResource --- intervention/admin.py | 27 ++++++++- intervention/models.py | 58 ++++++++++++++----- .../templates/intervention/detail/view.html | 22 +++---- konova/models.py | 13 ++++- konova/views.py | 2 +- 5 files changed, 90 insertions(+), 32 deletions(-) diff --git a/intervention/admin.py b/intervention/admin.py index 6d0df042..4adf095e 100644 --- a/intervention/admin.py +++ b/intervention/admin.py @@ -1,17 +1,38 @@ from django.contrib import admin -from intervention.models import Intervention +from intervention.models import Intervention, ResponsibilityData, LegalData class InterventionAdmin(admin.ModelAdmin): list_display = [ "id", "title", - "process_type", - "handler", "created_on", "deleted_on", ] +class ResponsibilityAdmin(admin.ModelAdmin): + list_display = [ + "id", + "registration_office", + "registration_file_number", + "conservation_office", + "conservation_file_number", + "handler", + ] + + +class LegalAdmin(admin.ModelAdmin): + list_display = [ + "id", + "process_type", + "law", + "registration_date", + "binding_date", + ] + + admin.site.register(Intervention, InterventionAdmin) +admin.site.register(ResponsibilityData, ResponsibilityAdmin) +admin.site.register(LegalData, LegalAdmin) diff --git a/intervention/models.py b/intervention/models.py index 5280c840..67fd83a4 100644 --- a/intervention/models.py +++ b/intervention/models.py @@ -12,33 +12,61 @@ from django.utils import timezone from django.utils.timezone import now from intervention.settings import INTERVENTION_IDENTIFIER_LENGTH, INTERVENTION_IDENTIFIER_TEMPLATE -from konova.models import BaseObject, Geometry +from konova.models import BaseObject, Geometry, UuidModel from konova.utils.generators import generate_random_string from organisation.models import Organisation from user.models import UserActionLogEntry +class ResponsibilityData(UuidModel): + """ + Holds intervention data about responsible organizations and their file numbers for this case + + """ + registration_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+") + registration_file_number = models.CharField(max_length=1000, blank=True, null=True) + conservation_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+") + 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'") + + +class LegalData(UuidModel): + """ + Holds intervention legal data such as important dates, laws or responsible handler + """ + # Refers to "zugelassen am" + registration_date = models.DateField(null=True, blank=True, help_text="Refers to 'Zugelassen am'") + + # Refers to "Bestandskraft am" + binding_date = models.DateField(null=True, blank=True, help_text="Refers to 'Bestandskraft am'") + + process_type = models.CharField(max_length=500, null=True, blank=True) + law = models.CharField(max_length=500, null=True, blank=True) + + class Intervention(BaseObject): """ Interventions are e.g. construction sites where nature used to be. """ - registration_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+") - registration_file_number = models.CharField(max_length=1000, blank=True, null=True) - conservation_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+") - conservation_file_number = models.CharField(max_length=1000, blank=True, null=True) - - process_type = models.CharField(max_length=500, null=True, blank=True) - law = models.CharField(max_length=500, null=True, blank=True) - handler = models.CharField(max_length=500, null=True, blank=True, help_text="Who is responsible for this intervention?") + responsible = models.OneToOneField( + ResponsibilityData, + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name='+', + help_text="Holds data on responsible organizations ('Zulassungsbehörde', 'Eintragungsstelle')" + ) + legal = models.OneToOneField( + LegalData, + on_delete=models.SET_NULL, + null=True, + blank=True, + related_name='+', + help_text="Holds data on legal dates or law" + ) geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) - # Refers to "zugelassen am" - registration_date = models.DateField(null=True, blank=True) - - # Refers to "Bestandskraft am" - binding_on = models.DateField(null=True, blank=True) - # Checks - Refers to "Genehmigen" but optional checked = models.OneToOneField( UserActionLogEntry, diff --git a/intervention/templates/intervention/detail/view.html b/intervention/templates/intervention/detail/view.html index e19d3c16..7354bca1 100644 --- a/intervention/templates/intervention/detail/view.html +++ b/intervention/templates/intervention/detail/view.html @@ -64,31 +64,31 @@ {% trans 'Process type' %} - {{intervention.process_type|default_if_none:""}} + {{intervention.legal.process_type|default_if_none:""}} {% trans 'Law' %} - {{intervention.law|default_if_none:""}} + {{intervention.legal.law|default_if_none:""}} {% trans 'Registration office' %} - {{intervention.registration_office|default_if_none:""}} + {{intervention.responsible.registration_office|default_if_none:""}} {% trans 'Registration office file number' %} - {{intervention.registration_file_number|default_if_none:""}} + {{intervention.responsible.registration_file_number|default_if_none:""}} {% trans 'Conservation office' %} - {{intervention.conservation_office|default_if_none:""}} + {{intervention.responsible.conservation_office|default_if_none:""}} {% trans 'Conversation office file number' %} - {{intervention.conservation_file_number|default_if_none:""}} + {{intervention.responsible.conservation_file_number|default_if_none:""}} {% trans 'Intervention handler' %} - {{intervention.handler|default_if_none:""}} + {{intervention.responsible.handler|default_if_none:""}} {% trans 'Checked' %} @@ -98,7 +98,7 @@ {% fa5_icon 'star' 'far' %} {% else %} - + {% fa5_icon 'star' %} {% endif %} @@ -112,7 +112,7 @@ {% fa5_icon 'bookmark' 'far' %} {% else %} - + {% fa5_icon 'bookmark' %} {% endif %} @@ -120,11 +120,11 @@ {% trans 'Registration date' %} - {{intervention.registration_date|default_if_none:""}} + {{intervention.legal.registration_date|default_if_none:""}} {% trans 'Binding on' %} - {{intervention.binding_on|default_if_none:""}} + {{intervention.legal.binding_on|default_if_none:""}} {% trans 'Last modified' %} diff --git a/konova/models.py b/konova/models.py index 0d4d79a7..53d7bcca 100644 --- a/konova/models.py +++ b/konova/models.py @@ -15,14 +15,23 @@ from django.db import models from konova.settings import DEFAULT_SRID -class BaseResource(models.Model): +class UuidModel(models.Model): """ - A basic resource model, which defines attributes for every derived model + Encapsules identifying via uuid """ id = models.UUIDField( primary_key=True, default=uuid.uuid4, ) + + class Meta: + abstract = True + + +class BaseResource(UuidModel): + """ + A basic resource model, which defines attributes for every derived model + """ created_on = models.DateTimeField(auto_now_add=True, null=True) created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name="+") diff --git a/konova/views.py b/konova/views.py index df11a1e0..e857d092 100644 --- a/konova/views.py +++ b/konova/views.py @@ -78,7 +78,7 @@ def home_view(request: HttpRequest): next_version=None, ) user_comps = comps.filter( - users__in=[user] + intervention__users__in=[user] ) eco_accs = EcoAccount.objects.filter( deleted_on=None, From e9f25e50ac2744f96c77d2fe916a4e819ce6de3f Mon Sep 17 00:00:00 2001 From: mipel Date: Fri, 30 Jul 2021 12:20:23 +0200 Subject: [PATCH 4/4] Compensation model refactoring * splits Intervention model into main components * Compensation (main object) * ResponsibilityData (holds organizations and handler) - same as used for intervention * This way data can be extended more easily in the future * refactors deadlines --- compensation/models.py | 27 +++++++++++++-------------- konova/admin.py | 12 +++++++++++- konova/enums.py | 6 ++++++ konova/models.py | 4 +++- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/compensation/models.py b/compensation/models.py index f83e598e..e7c439b5 100644 --- a/compensation/models.py +++ b/compensation/models.py @@ -12,8 +12,8 @@ from django.utils import timezone from django.utils.timezone import now from compensation.settings import COMPENSATION_IDENTIFIER_LENGTH, COMPENSATION_IDENTIFIER_TEMPLATE -from intervention.models import Intervention -from konova.models import BaseObject, BaseResource, Geometry +from intervention.models import Intervention, ResponsibilityData +from konova.models import BaseObject, BaseResource, Geometry, UuidModel from konova.utils.generators import generate_random_string from organisation.models import Organisation @@ -73,18 +73,19 @@ class Compensation(BaseObject): The compensation holds information about which actions have to be performed until which date, who is in charge of this, which legal authority is the point of contact, and so on. """ - registration_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+") - conservation_office = models.ForeignKey(Organisation, on_delete=models.SET_NULL, null=True, related_name="+") + responsible = models.OneToOneField( + ResponsibilityData, + on_delete=models.SET_NULL, + null=True, + blank=True, + help_text="Holds data on responsible organizations ('Zulassungsbehörde', 'Eintragungsstelle') and handler", + ) - ground_definitions = models.CharField(max_length=500, null=True, blank=True) # ToDo: Need to be M2M to laws! - action_definitions = models.CharField(max_length=500, null=True, blank=True) # ToDo: Need to be M2M to laws! + before_states = models.ManyToManyField(CompensationState, blank=True, related_name='+', help_text="Refers to 'Ausgangszustand Biotop'") + after_states = models.ManyToManyField(CompensationState, blank=True, related_name='+', help_text="Refers to 'Zielzustand Biotop'") + actions = models.ManyToManyField(CompensationAction, help_text="Refers to 'Maßnahmen'") - before_states = models.ManyToManyField(CompensationState, blank=True, related_name='+') - after_states = models.ManyToManyField(CompensationState, blank=True, related_name='+') - actions = models.ManyToManyField(CompensationAction) - - deadline_creation = models.ForeignKey("konova.Deadline", on_delete=models.SET_NULL, null=True, blank=True, related_name="+") - deadline_maintaining = models.ForeignKey("konova.Deadline", on_delete=models.SET_NULL, null=True, blank=True, related_name="+") + deadlines = models.ManyToManyField("konova.Deadline", null=True, blank=True, related_name="+") geometry = models.ForeignKey(Geometry, null=True, blank=True, on_delete=models.SET_NULL) documents = models.ManyToManyField("konova.Document", blank=True) @@ -149,7 +150,5 @@ class EcoAccount(Compensation): An eco account is a kind of 'prepaid' compensation. It can be compared to an account that already has been filled with some kind of currency. From this account one is able to 'withdraw' currency for current projects. """ - handler = models.CharField(max_length=500, null=True, blank=True, help_text="Who is responsible for handling the actions") - # Users having access on this object users = models.ManyToManyField(User) diff --git a/konova/admin.py b/konova/admin.py index 6fc31b76..e53a7fa3 100644 --- a/konova/admin.py +++ b/konova/admin.py @@ -7,7 +7,7 @@ Created on: 22.07.21 """ from django.contrib import admin -from konova.models import Geometry, Document +from konova.models import Geometry, Document, Deadline class GeometryAdmin(admin.ModelAdmin): @@ -28,5 +28,15 @@ class DocumentAdmin(admin.ModelAdmin): ] +class DeadlineAdmin(admin.ModelAdmin): + list_display = [ + "id", + "type", + "date", + "comment", + ] + + admin.site.register(Geometry, GeometryAdmin) admin.site.register(Document, DocumentAdmin) +admin.site.register(Deadline, DeadlineAdmin) diff --git a/konova/enums.py b/konova/enums.py index 1f54cf9a..f2209350 100644 --- a/konova/enums.py +++ b/konova/enums.py @@ -55,3 +55,9 @@ class UserActionLogEntryEnum(BaseEnum): """ CHECKED = "Checked" RECORDED = "Recorded" + + +class DeadlineTypeEnum(BaseEnum): + MAINTAIN = "Maintain" + CONTROL = "Control" + OTHER = "Other" \ No newline at end of file diff --git a/konova/models.py b/konova/models.py index 53d7bcca..e47764f7 100644 --- a/konova/models.py +++ b/konova/models.py @@ -12,6 +12,7 @@ from django.contrib.auth.models import User from django.contrib.gis.db.models import MultiPolygonField from django.db import models +from konova.enums import DeadlineTypeEnum from konova.settings import DEFAULT_SRID @@ -59,8 +60,9 @@ class Deadline(BaseResource): """ Defines a deadline, which can be used to define dates with a semantic meaning """ - type = models.CharField(max_length=500, null=True, blank=True) + type = models.CharField(max_length=255, null=True, blank=True, choices=DeadlineTypeEnum.as_choices(drop_empty_choice=True)) date = models.DateField(null=True, blank=True) + comment = models.CharField(max_length=1000, null=True, blank=True) def __str__(self): return self.type