#31 API code cleaning

* splits large AbstractModelAPISerializer into different reusable Mixins to increase reusability of code for similar models
This commit is contained in:
mpeltriaux 2022-01-24 15:20:23 +01:00
parent 02e72e015f
commit 07331078c4
5 changed files with 212 additions and 182 deletions

View File

@ -7,16 +7,15 @@ Created on: 24.01.22
"""
from django.db import transaction
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID
from compensation.models import Compensation, CompensationAction, CompensationState, UnitChoices
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, AbstractCompensationAPISerializerV1Mixin
from compensation.models import Compensation
from intervention.models import Intervention
from konova.models import Geometry, Deadline, DeadlineType
from konova.models import Geometry
from konova.tasks import celery_update_parcels
from user.models import UserActionLogEntry
class CompensationAPISerializerV1(AbstractModelAPISerializerV1):
class CompensationAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISerializerV1Mixin):
model = Compensation
def prepare_lookup(self, id, user):
@ -88,122 +87,6 @@ class CompensationAPISerializerV1(AbstractModelAPISerializerV1):
obj.intervention = intervention
return obj
def set_deadlines(self, obj, deadline_data):
""" Sets the linked deadline data according to the given deadline_data
Args:
obj (Compensation): The Compensation object
deadline_data (dict): The posted deadline_data
Returns:
obj (Compensation)
"""
found_deadlines = []
for entry in deadline_data:
deadline_type = entry["type"]
date = entry["date"]
comment = entry["comment"]
if deadline_type not in DeadlineType:
raise ValueError(f"Invalid deadline type. Choices are {DeadlineType.values}")
pre_existing_deadlines = obj.deadlines.filter(
type=deadline_type,
date=date,
comment=comment,
).exclude(
id__in=found_deadlines
)
if pre_existing_deadlines.count() > 0:
found_deadlines += pre_existing_deadlines.values_list("id", flat=True)
else:
# Create!
new_deadline = Deadline.objects.create(
type=deadline_type,
date=date,
comment=comment,
)
obj.deadlines.add(new_deadline)
return obj
def set_compensation_states(self, obj, states_data, states_manager):
""" Sets the linked compensation state data according to the given states_data
Args:
obj (Compensation): The Compensation object
states_data (dict): The posted states_data
states_manager (Manager): The before_states or after_states manager
Returns:
obj (Compensation)
"""
found_states = []
for entry in states_data:
biotope_type = entry["biotope"]
surface = float(entry["surface"])
if surface <= 0:
raise ValueError("State surfaces must be > 0")
pre_existing_states = states_manager.filter(
biotope_type__atom_id=biotope_type,
surface=surface,
).exclude(
id__in=found_states
)
if pre_existing_states.count() > 0:
found_states += pre_existing_states.values_list("id", flat=True)
else:
# Create!
new_state = CompensationState.objects.create(
biotope_type=self.konova_code_from_json(biotope_type, CODELIST_BIOTOPES_ID),
surface=surface
)
states_manager.add(new_state)
return obj
def set_compensation_actions(self, obj, actions_data):
""" Sets the linked compensation action data according to the given actions_data
Args:
obj (Compensation): The Compensation object
actions_data (dict): The posted actions_data
Returns:
obj (Compensation)
"""
found_actions = []
for entry in actions_data:
action = entry["action"]
amount = float(entry["amount"])
unit = entry["unit"]
comment = entry["comment"]
if amount <= 0:
raise ValueError("Action amount must be > 0")
if unit not in UnitChoices:
raise ValueError(f"Invalid unit. Choices are {UnitChoices.values}")
pre_existing_actions = obj.actions.filter(
action_type__atom_id=action,
amount=amount,
unit=unit,
comment=comment,
).exclude(
id__in=found_actions
)
if pre_existing_actions.count() > 0:
found_actions += pre_existing_actions.values_list("id", flat=True)
else:
# Create!
new_action = CompensationAction.objects.create(
action_type=self.konova_code_from_json(action, CODELIST_COMPENSATION_ACTION_ID),
amount=amount,
unit=unit,
comment=comment,
)
obj.actions.add(new_action)
return obj
def create_model_from_json(self, json_model, user):
""" Creates a new entry for the model based on the contents of json_model

View File

@ -5,12 +5,17 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 24.01.22
"""
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, AbstractCompensationAPISerializerV1Mixin, \
LegalAPISerializerV1Mixin, ResponsibilityAPISerializerV1Mixin, DeductableAPISerializerV1Mixin
from compensation.models import EcoAccount
from intervention.models import Legal, Responsibility
class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1):
class EcoAccountAPISerializerV1(AbstractModelAPISerializerV1,
AbstractCompensationAPISerializerV1Mixin,
LegalAPISerializerV1Mixin,
ResponsibilityAPISerializerV1Mixin,
DeductableAPISerializerV1Mixin):
model = EcoAccount
def extend_properties_data(self, entry):

View File

@ -5,12 +5,13 @@ Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 24.01.22
"""
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, AbstractCompensationAPISerializerV1Mixin, \
ResponsibilityAPISerializerV1Mixin
from ema.models import Ema
from intervention.models import Responsibility
class EmaAPISerializerV1(AbstractModelAPISerializerV1):
class EmaAPISerializerV1(AbstractModelAPISerializerV1, AbstractCompensationAPISerializerV1Mixin, ResponsibilityAPISerializerV1Mixin):
model = Ema
def responsible_to_json(self, responsible: Responsibility):

View File

@ -8,7 +8,8 @@ Created on: 24.01.22
from django.db import transaction
from django.db.models import QuerySet
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1
from api.utils.serializer.v1.serializer import AbstractModelAPISerializerV1, \
ResponsibilityAPISerializerV1Mixin, LegalAPISerializerV1Mixin
from codelist.settings import CODELIST_CONSERVATION_OFFICE_ID, CODELIST_REGISTRATION_OFFICE_ID, \
CODELIST_PROCESS_TYPE_ID, CODELIST_LAW_ID
from intervention.models import Intervention, Responsibility, Legal
@ -17,7 +18,7 @@ from konova.tasks import celery_update_parcels
from user.models import UserActionLogEntry
class InterventionAPISerializerV1(AbstractModelAPISerializerV1):
class InterventionAPISerializerV1(AbstractModelAPISerializerV1, ResponsibilityAPISerializerV1Mixin, LegalAPISerializerV1Mixin):
model = Intervention
def compensations_to_json(self, qs: QuerySet):
@ -27,6 +28,17 @@ class InterventionAPISerializerV1(AbstractModelAPISerializerV1):
)
)
def payments_to_json(self, qs: QuerySet):
""" Serializes payments into json
Args:
qs (QuerySet): A queryset of Payment entries
Returns:
serialized_json (list)
"""
return list(qs.values("amount", "due_on", "comment"))
def extend_properties_data(self, entry):
self.properties_data["responsible"] = self.responsible_to_json(entry.responsible)
self.properties_data["legal"] = self.legal_to_json(entry.legal)

View File

@ -12,7 +12,10 @@ from django.db.models import QuerySet
from api.utils.serializer.serializer import AbstractModelAPISerializer
from codelist.models import KonovaCode
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID
from compensation.models import CompensationAction, UnitChoices, CompensationState
from intervention.models import Responsibility, Legal
from konova.models import Deadline, DeadlineType
class AbstractModelAPISerializerV1(AbstractModelAPISerializer):
@ -71,49 +74,34 @@ class AbstractModelAPISerializerV1(AbstractModelAPISerializer):
)
return code
def responsible_to_json(self, responsible: Responsibility):
""" Serializes Responsibility model into json
def created_on_to_json(self, entry):
""" Serializes the created_on into json
Args:
responsible (Responsibility): The Responsibility entry
entry (BaseObject): The entry
Returns:
serialized_json (dict)
created_on (timestamp)
"""
return {
"registration_office": self.konova_code_to_json(responsible.registration_office),
"registration_file_number": responsible.registration_file_number,
"conservation_office": self.konova_code_to_json(responsible.conservation_office),
"conservation_file_number": responsible.conservation_file_number,
"handler": responsible.handler,
}
return entry.created.timestamp
def legal_to_json(self, legal: Legal):
""" Serializes Legal model into json
def modified_on_to_json(self, entry):
""" Serializes the modified_on into json
Args:
legal (Legal): The Legal entry
entry (BaseObject): The entry
Returns:
serialized_json (dict)
modified_on (timestamp)
"""
return {
"registration_date": legal.registration_date,
"binding_date": legal.binding_date,
"process_type": self.konova_code_to_json(legal.process_type),
"laws": [self.konova_code_to_json(law) for law in legal.laws.all()],
}
modified_on = entry.modified or entry.created
modified_on = modified_on.timestamp
return modified_on
def payments_to_json(self, qs: QuerySet):
""" Serializes payments into json
Args:
qs (QuerySet): A queryset of Payment entries
Returns:
serialized_json (list)
"""
return list(qs.values("amount", "due_on", "comment"))
class DeductableAPISerializerV1Mixin:
class Meta:
abstract = True
def deductions_to_json(self, qs: QuerySet):
""" Serializes eco account deductions into json
@ -142,6 +130,171 @@ class AbstractModelAPISerializerV1(AbstractModelAPISerializer):
for entry in qs
]
class ResponsibilityAPISerializerV1Mixin:
class Meta:
abstract = True
def responsible_to_json(self, responsible: Responsibility):
""" Serializes Responsibility model into json
Args:
responsible (Responsibility): The Responsibility entry
Returns:
serialized_json (dict)
"""
return {
"registration_office": self.konova_code_to_json(responsible.registration_office),
"registration_file_number": responsible.registration_file_number,
"conservation_office": self.konova_code_to_json(responsible.conservation_office),
"conservation_file_number": responsible.conservation_file_number,
"handler": responsible.handler,
}
class LegalAPISerializerV1Mixin:
class Meta:
abstract = True
def legal_to_json(self, legal: Legal):
""" Serializes Legal model into json
Args:
legal (Legal): The Legal entry
Returns:
serialized_json (dict)
"""
return {
"registration_date": legal.registration_date,
"binding_date": legal.binding_date,
"process_type": self.konova_code_to_json(legal.process_type),
"laws": [self.konova_code_to_json(law) for law in legal.laws.all()],
}
class AbstractCompensationAPISerializerV1Mixin:
class Meta:
abstract = True
def set_deadlines(self, obj, deadline_data):
""" Sets the linked deadline data according to the given deadline_data
Args:
obj (Compensation): The Compensation object
deadline_data (dict): The posted deadline_data
Returns:
obj (Compensation)
"""
found_deadlines = []
for entry in deadline_data:
deadline_type = entry["type"]
date = entry["date"]
comment = entry["comment"]
if deadline_type not in DeadlineType:
raise ValueError(f"Invalid deadline type. Choices are {DeadlineType.values}")
pre_existing_deadlines = obj.deadlines.filter(
type=deadline_type,
date=date,
comment=comment,
).exclude(
id__in=found_deadlines
)
if pre_existing_deadlines.count() > 0:
found_deadlines += pre_existing_deadlines.values_list("id", flat=True)
else:
# Create!
new_deadline = Deadline.objects.create(
type=deadline_type,
date=date,
comment=comment,
)
obj.deadlines.add(new_deadline)
return obj
def set_compensation_states(self, obj, states_data, states_manager):
""" Sets the linked compensation state data according to the given states_data
Args:
obj (Compensation): The Compensation object
states_data (dict): The posted states_data
states_manager (Manager): The before_states or after_states manager
Returns:
obj (Compensation)
"""
found_states = []
for entry in states_data:
biotope_type = entry["biotope"]
surface = float(entry["surface"])
if surface <= 0:
raise ValueError("State surfaces must be > 0")
pre_existing_states = states_manager.filter(
biotope_type__atom_id=biotope_type,
surface=surface,
).exclude(
id__in=found_states
)
if pre_existing_states.count() > 0:
found_states += pre_existing_states.values_list("id", flat=True)
else:
# Create!
new_state = CompensationState.objects.create(
biotope_type=self.konova_code_from_json(biotope_type, CODELIST_BIOTOPES_ID),
surface=surface
)
states_manager.add(new_state)
return obj
def set_compensation_actions(self, obj, actions_data):
""" Sets the linked compensation action data according to the given actions_data
Args:
obj (Compensation): The Compensation object
actions_data (dict): The posted actions_data
Returns:
obj (Compensation)
"""
found_actions = []
for entry in actions_data:
action = entry["action"]
amount = float(entry["amount"])
unit = entry["unit"]
comment = entry["comment"]
if amount <= 0:
raise ValueError("Action amount must be > 0")
if unit not in UnitChoices:
raise ValueError(f"Invalid unit. Choices are {UnitChoices.values}")
pre_existing_actions = obj.actions.filter(
action_type__atom_id=action,
amount=amount,
unit=unit,
comment=comment,
).exclude(
id__in=found_actions
)
if pre_existing_actions.count() > 0:
found_actions += pre_existing_actions.values_list("id", flat=True)
else:
# Create!
new_action = CompensationAction.objects.create(
action_type=self.konova_code_from_json(action, CODELIST_COMPENSATION_ACTION_ID),
amount=amount,
unit=unit,
comment=comment,
)
obj.actions.add(new_action)
return obj
def compensation_state_to_json(self, qs: QuerySet):
""" Serializes compensation states into json
@ -192,27 +345,3 @@ class AbstractModelAPISerializerV1(AbstractModelAPISerializer):
"date",
"comment",
))
def created_on_to_json(self, entry):
""" Serializes the created_on into json
Args:
entry (BaseObject): The entry
Returns:
created_on (timestamp)
"""
return entry.created.timestamp
def modified_on_to_json(self, entry):
""" Serializes the modified_on into json
Args:
entry (BaseObject): The entry
Returns:
modified_on (timestamp)
"""
modified_on = entry.modified or entry.created
modified_on = modified_on.timestamp
return modified_on