[英]How to (de)serialize float list into models using Django REST Framework model serializer?
How to create both serializers.Patient
and serializers.Temperature
in such way that:如何以以下方式同时创建serializers.Patient
和serializers.Temperature
:
models.Patient
has one-to-many relationship with models.Temperatures
models.Patient
与models.Temperatures
是一对多的关系serializers.Patient
is a subclass of serializers.ModelSerializer
serializers.Patient
是serializers.ModelSerializer
的子类serializers.Patient
(de)serialize temperatures as a list of floats serializers.Patient
(反)将温度序列化为浮点数列表Given a quick-dirty patient medical records RESTful API implemented with Django framework .给定一个快速脏的患者病历 RESTful API 使用Django 框架实现。
Patient is defined at models.Patient
as:患者在models.Patient
中定义为:
class Patient(models.Model):
created_at = models.DateField()
name = models.CharField(max_length=200)
updated_at = models.DateField()
and the models.Temperature
:和models.Temperature
:
class Temperature(models.Model):
created_at = models.DateField()
patient = models.ForeignKey(
Patient,
db_column='patient',
related_name='temperatures',
on_delete=models.CASCADE,
)
updated_at = models.DateField()
CRUD operations at /patients
(de)serialized models.Temperature
as float
lists, thus a POST
should only require: /patients
(de)serialized models.Temperature
作为float
列表的 CRUD 操作,因此POST
应该只需要:
{
"name": "John Connor",
"temperatures": [36.7, 40, 35.9]
}
while a GET
operation而GET
操作
{
"created_at": "1985-03-25",
"name": "John Connor",
"temperatures": [36.7, 40, 35.9],
"updated_at": "2021-08-29"
}
However operations at /patients/<id>/temperatures/
endpoint should return all properties :但是/patients/<id>/temperatures/
端点的操作应该返回所有属性:
[
{
"created_at": "1985-03-25",
"value": 36.7,
"updated_at": "2021-08-29"
},
{
"created_at": "1985-03-25",
"value": 40.0,
"updated_at": "2021-08-29"
},
{
"created_at": "1985-03-25",
"value": 35.9,
"updated_at": "2021-08-29"
}
]
Can this feature be implemented subclassing standards DRF serializers or does it require a customized serializers.Serializer
subclass?可以通过子类化标准DRF序列化程序来实现此功能,还是需要自定义的serializers.Serializer
程序。序列化程序子类?
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.因此,让我们为此目的使用ListField
。 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.但是在使用GET
操作时,我们将如何获取创建的患者的温度数组。 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: source
参数上写的任何内容都将转换为patient.field
,例如:
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:这个source="temperature_list
将使用patient.temperature_list
并在序列化 object 时显示结果。现在让我们在原始 model 中添加一些属性,以便我们可以像这样获得干净的温度数组:
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.现在我们需要重写PatientSerializer
的create
方法,以便它可以保存列表中的温度。 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
.现在,要从validated_data
获取温度数据,我们需要使用与ListField
的source
参数中使用的字段相同的字段,即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:让我们像这样创建一个TemperatureSerializer
:
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.现在,我们需要做的就是编写 create 方法。 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:最后,让我们把所有的东西放在一起,这就是serializers.py
文件的样子:
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:这就是views.py
的样子:
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:和urls.py
文件:
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:这就是POST
方法的工作方式:
And this is how the temperatures of a patient would return:这就是病人体温恢复的方式:
I hope this answers your questions.我希望这回答了你的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.