简体   繁体   English

如何使用 Django REST Framework model 序列化程序将浮点列表(反)序列化为模型?

[英]How to (de)serialize float list into models using Django REST Framework model serializer?

TL; TL; DR博士

How to create both serializers.Patient and serializers.Temperature in such way that:如何以以下方式同时创建serializers.Patientserializers.Temperature

  1. models.Patient has one-to-many relationship with models.Temperatures models.Patientmodels.Temperatures是一对多的关系
  2. serializers.Patient is a subclass of serializers.ModelSerializer serializers.Patientserializers.ModelSerializer的子类
  3. serializers.Patient (de)serialize temperatures as a list of floats serializers.Patient (反)将温度序列化为浮点数列表

Details细节

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 operationGET操作

{
  "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.现在我们需要重写PatientSerializercreate方法,以便它可以保存列表中的温度。 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获取温度数据,我们需要使用与ListFieldsource参数中使用的字段相同的字段,即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.

相关问题 如何使用Django Rest Framework将多个模型序列化为一个用于层次结构的序列化器? - How to serialize multiple models into one serializer for hierarchy structure using Django Rest Framework? 如何在 django rest 框架序列化程序中序列化布尔值列表? - How can I serialize list of booleans in django rest framework serializer? 如何使用django rest_framework序列化带有直通模型的ManyToManyFields - How to serialize using django rest_framework a ManyToManyFields with a Through Model 如何在包含另一个序列化程序(模型)、django rest 框架的序列化程序中创建自定义列表字段? - How to create custom list field in serializer, which contains another serializer(model), django rest framework? 如何在 django-rest-framework 的序列化器中使用时区序列化时间? - how to serialize time with timezone in django-rest-framework's serializer? Django Rest Framework:如何序列化列表列表? - Django Rest Framework: How serialize list of list? Django Rest框架如何序列化一个关系Model? - Django Rest Framework how to serialize a relational Model? 如何使用Model serializer在django-rest中序列化一对多关系? - How to serialize a one to many relation in django-rest using Model serializer? Django Rest Framework如何从多个模型创建Serializer - Django Rest Framework how to create Serializer from multiple models Django rest框架如何序列化字符串列表? - Django rest framework how to serialize a list of strings?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM