5👍
Let’s try to analyze the situation here. We need to input the temperature data with a list. So, let’s use ListField
for this purpose. So, we should start like this:
class PatientSerializer(ModelSerializer):
temperatures = ListField(child=FloatField())
What this will do is expect a list of floats from the user.
But how will we get the array of the temperatures of the created patient when using GET
operation. For this, let’s add a source to the field. Whatever is written on the source
param will get converted into the patient.field
for example:
class PatientSerializer(ModelSerializer):
temperatures = ListField(child=FloatField(), source="temperature_list")
This source="temperature_list
will user patient.temperature_list
and show the result when serializing the object. Now let’s add some property to the original model so that we can get the clean temperature array like this:
class Patient(models.Model):
created_at = models.DateField()
name = models.CharField(max_length=200)
updated_at = models.DateField()
@property
def temperature_list(self):
return [temperature.value for temperature in self.temperatures.all()]
We are almost done. Now we need to override the create
method for PatientSerializer
so that it can save the temperatures present in the list.
Now, to get the temperature data from the validated_data
we need to use the same field that is used in the source
argument on the ListField
, which is temperature_list
. So, we need to pop this data, create the user, validate the temperature list items, create temperature objects that are related to the patient. Let’s create a TemperatureSerializer
like this:
class TemperatureSerializer(ModelSerializer):
class Meta:
model = Temperature
fields = ("created_at", "value", "updated_at", "patient")
extra_kwargs = {
"patient": {"write_only": True},
"created_at": {"required": False},
"updated_at": {"required": False},
}
Now, all we need to do is, write the create method. We can write it like this:
def create(self, validated_data):
temperatures = validated_data.pop("temperature_list")
now = datetime.now().strftime("%Y-%m-%d")
patient = Patient.objects.create(
created_at=now, updated_at=now, **validated_data
)
for temperature in temperatures:
now = datetime.now().strftime("%Y-%m-%d")
temperature_serializer = TemperatureSerializer(
data={
"value": temperature,
"created_at": now,
"updated_at": now,
"patient": patient.id,
}
)
temperature_serializer.is_valid(raise_exception=True)
temperature_serializer.save()
return patient
Finally, let’s put together all the things and this is how the serializers.py
file would look like:
from rest_framework.serializers import ModelSerializer, ListField, FloatField
from datetime import datetime
from .models import Patient, Temperature
class TemperatureSerializer(ModelSerializer):
class Meta:
model = Temperature
fields = ("created_at", "value", "updated_at", "patient")
extra_kwargs = {
"patient": {"write_only": True},
"created_at": {"required": False},
"updated_at": {"required": False},
}
class PatientSerializer(ModelSerializer):
temperatures = ListField(child=FloatField(), source="temperature_list")
def create(self, validated_data):
temperatures = validated_data.pop("temperature_list")
now = datetime.now().strftime("%Y-%m-%d")
patient = Patient.objects.create(
created_at=now, updated_at=now, **validated_data
)
for temperature in temperatures:
now = datetime.now().strftime("%Y-%m-%d")
temperature_serializer = TemperatureSerializer(
data={
"value": temperature,
"created_at": now,
"updated_at": now,
"patient": patient.id,
}
)
temperature_serializer.is_valid(raise_exception=True)
temperature_serializer.save()
return patient
class Meta:
model = Patient
fields = ("created_at", "name", "temperatures", "updated_at")
extra_kwargs = {
"created_at": {"required": False},
"updated_at": {"required": False},
}
This is how the views.py
would look like:
from rest_framework.generics import ListCreateAPIView, ListAPIView
from .models import Patient, Temperature
from .serializers import PatientSerializer, TemperatureSerializer
class PatientListCreateView(ListCreateAPIView):
serializer_class = PatientSerializer
queryset = Patient.objects.all()
class TemperatureListView(ListAPIView):
serializer_class = TemperatureSerializer
def get_queryset(self, *args, **kwargs):
patient_id = self.kwargs["pk"]
return Temperature.objects.filter(patient_id=patient_id)
And the urls.py
file:
from django.urls import path
from . import views
urlpatterns = [
path("patients", views.PatientListCreateView.as_view(), name="patient-list"),
path(
"patients/<int:pk>/temperatures/",
views.TemperatureListView.as_view(),
name="patient-temperature-list",
),
]
This is how the POST
method would work:
And this is how the temperatures of a patient would return:
I hope this answers your questions.