drdown/medicalrecords/views/view_curves.py
from django.contrib import messages
from django.db import IntegrityError, transaction
from django.utils.translation import ugettext_lazy as _
from ..models.model_curves import Curves
from drdown.users.models.model_patient import Patient
from django.views.generic import CreateView, UpdateView, View
from ..forms.curves_form import CurvesForm
from ..views.views_base import (
BaseViewUrl,
BaseViewPermissions,
BaseViewPermissionPatientResponsible
)
from django.shortcuts import get_object_or_404, redirect, render
from django.http import (
HttpResponse,
HttpResponseForbidden,
JsonResponse,
)
from django.urls import reverse, reverse_lazy
from urllib import parse, request as urlrequest
import json
from math import floor
class FormValid():
def form_valid(self, form):
form.instance.patient = Patient.objects.get(
user__username=self.kwargs.get('username')
)
form.save()
return super().form_valid(form)
class CurvesCreateView(
FormValid, BaseViewPermissions, BaseViewUrl, CreateView
):
model = Curves
form_class = CurvesForm
template_name = 'medicalrecords/medicalrecord_curves_form.html'
def post(self, request, *args, **kwargs):
try:
with transaction.atomic():
data = super().post(request, *args, **kwargs)
return data
except IntegrityError:
messages.add_message(request, messages.ERROR,
_('The patient already has a curve at this '
'age. If wanted, just change its data.'))
return render(request, template_name=self.template_name,
context=self.get_context_data())
class CurvesUpdateView(
BaseViewPermissions, BaseViewUrl, UpdateView
):
model = Curves
form_class = CurvesForm
template_name = 'medicalrecords/medicalrecord_curves_form.html'
class CurveDataParser(BaseViewPermissionPatientResponsible, View):
api_port = ":8000"
patient = None
data_type = None
api_url = None
drdown_data = None
api_data = None
time_frame = None
DATA_TYPE_TRANSLATIONS = {
'bmi': _("BMI"),
'weight': _("Weight"),
'height': _("Height"),
'cephalic_perimeter': _("Cephalic Perimeter"),
'months': _("Age (in months)"),
'years': _("Age (in years)"),
}
def get(self, request, *args, **kwargs):
self.patient = Patient.objects.filter(
user__username=request.GET.get('username')
).first()
self.data_type = request.GET.get('data_type')
self.time_frame = request.GET.get('time_frame')
self.api_url = self.get_api_url(request)
self.drdown_data = self.get_drdown_data()
self.api_data = self.get_api_data()
return JsonResponse({'data': self.combine_data()})
@staticmethod
def get_curves(patient):
return Curves.objects.filter(patient=patient)
@staticmethod
def get_curve_data(curves, attr):
data = []
for curve in curves:
# tuple, 0 == age, 1 == value
curve_data = (curve.age, getattr(curve, attr))
data.append(curve_data)
return data
def get_drdown_data(self):
curves = self.get_curves(self.patient)
return self.get_curve_data(curves, self.data_type)
def get_api_url(self, request):
# get the current addres and add service port
url = parse.urlparse(request.build_absolute_uri())
return str(url.netloc) + self.api_port
def api_data_type(self):
if self.data_type == "bmi":
return "imc"
elif self.data_type == "cephalic_perimeter":
return "perimeter"
else:
return self.data_type
def api_gender(self):
gender = self.patient.user.gender
if gender in ["M", "Male"]:
return "male"
else:
return "female"
def api_time_frame(self):
if self.data_type == "bmi":
return "years"
elif self.data_type == "cephalic_perimeter":
return "months"
return self.time_frame
def get_api_directory(self):
# API directory map:
# api/growth-curve/height/
# api/growth-curve/weight/
# [male-months, male-years, female-months, female-years, result]
# api/growth-curve/imc/
# api/growth-curve/perimeter/
# [male, female, result]
api_dir = (
"api/growth-curve/" + self.api_data_type() +
"/" + self.api_gender()
)
if self.api_data_type() not in ["imc", "perimeter"]:
api_dir += "-" + self.api_time_frame()
return api_dir
def get_api_data(self):
# Ideally, in place of the constant, one would use self.api_url
# but its not working right now
API_URL = "www.drdown-homolog.ml:8000"
url = "http://" + API_URL + "/" + self.get_api_directory()
# print("DEBUG >>> URL " + url)
# create a request and parse response as JSON
req = urlrequest.Request(url=url,)
opener = urlrequest.build_opener()
f = opener.open(req)
json_obj = json.loads(f.read())
return json_obj
def combine_data(self):
graphic = self.api_data['graphic']
# data is a tuple with 0 == patient age, 1 == value
for data in self.select_data():
# the index is age + 1, because the first line
# in the 'graphic' returned by the api is a Header line
# so it saves no values
age = data[0]
index = age if self.api_time_frame() == 'months' else floor(age/12)
if self.api_time_frame() == 'months':
index += 1
elif self.data_type in ['height', 'weight']:
index -= 2
else:
index -= 1
graph_list = graphic[index]
# the last element is the value
graph_list[-1] = data[1]
headers = graphic[0]
headers[0] = self.DATA_TYPE_TRANSLATIONS[self.api_time_frame()]
headers[-1] = self.DATA_TYPE_TRANSLATIONS[self.data_type]
return self.api_data
def select_data(self):
selected_curves = []
if self.api_time_frame() == 'months':
max_month = 24 if self.data_type == "cephalic_perimeter" else 36
# if we are asking for months, the API limit is 36
selected_curves = list(
filter(lambda x: x[0] <= max_month, self.drdown_data)
)
elif self.api_time_frame() == 'years':
MIN_YEAR = 2 if self.data_type == 'bmi' else 3
MAX_YEAR = 18
# get data with months bigger than MIN_YEAR
year_curves = list(
filter(lambda x: x[0] >= MIN_YEAR * 12, self.drdown_data)
)
# API years go from 3 to 18
for i in range(MIN_YEAR, MAX_YEAR):
# this line filter all curve points that belongs to a year
# ex: month 36 to month 48, then gets the last one of those
# this behaviour was defined bt management (instead os a mean)
specific_year_curves = [
x for x in year_curves
if (i * 12 <= x[0] < (i + 1) * 12)
]
selected_curves += specific_year_curves
# handy debug line, for the poor guy who will be doing maintenance
# here in the future:
# print("DEBUG >>>" + self.api_time_frame() + " " +
# self.get_api_directory() + " " + str(selected_curves))
return selected_curves