【问题标题】:How to code a float list ModelSerializer for DRF a model?如何为 DRF 模型编写浮点列表 ModelSerializer?
【发布时间】:2022-01-09 23:58:19
【问题描述】:

TL;博士

如何同时创建serializers.Patientserializers.Temperature,这样:

  1. models.Patientmodels.Temperatures 具有一对多关系
  2. serializers.Patientserializers.ModelSerializer 的子类
  3. serializers.Patient(反)将温度序列化为浮点列表

详情

给定一个使用Django framework 实现的quick-dirty患者医疗记录 RESTful API。

患者在models.Patient 中定义为:

class Patient(models.Model):
    created_at = models.DateField()
    name = models.CharField(max_length=200)
    updated_at = models.DateField()

还有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()
    value = models.FloatField()

/patients 的 CRUD 操作(反)序列化 models.Temperaturefloat 列表,因此 POST 应该只需要:

{
  "name": "John Connor",
  "temperatures": [36.7, 40, 35.9]
}

GET 操作时

{
  "created_at": "1985-03-25",
  "name": "John Connor",
  "temperatures": [36.7, 40, 35.9],
  "updated_at": "2021-08-29"
}

但是/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"
  }
]

此功能能否通过子类化标准 DRF 序列化程序实现,还是需要自定义 serializers.Serializer 子类?

【问题讨论】:

  • 我认为您的Temperature 模型缺少value 属性。

标签: python django django-models django-rest-framework


【解决方案1】:

让我们试着分析一下这里的情况。我们需要用列表输入温度数据。因此,让我们为此目的使用ListField。所以,我们应该这样开始:

class PatientSerializer(ModelSerializer):
    temperatures = ListField(child=FloatField())

这将做的是期待用户的浮动列表。 但是当使用GET 操作时,我们将如何获得创建的患者的温度数组。为此,让我们向该字段添加一个源。 source 参数上写的任何内容都将转换为 patient.field,例如:

class PatientSerializer(ModelSerializer):
    temperatures = ListField(child=FloatField(), source="temperature_list")

这个source="temperature_list 将使用patient.temperature_list 并在序列化对象时显示结果。现在让我们为原始模型添加一些属性,以便我们可以像这样获得干净的温度数组:

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()]

我们差不多完成了。现在我们需要覆盖PatientSerializercreate 方法,以便它可以保存列表中的温度。 现在,要从validated_data 获取温度数据,我们需要使用ListFieldsource 参数中使用的相同字段,即temperature_list。因此,我们需要弹出这些数据,创建用户,验证温度列表项,创建与患者相关的温度对象。让我们像这样创建一个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},
        }

现在,我们需要做的就是编写 create 方法。我们可以这样写:

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

最后,让我们把所有的东西放在一起,这就是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},
        }

这就是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)

还有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",
    ),
]

POST 方法的工作原理如下:

这就是患者体温恢复的方式:

我希望这能回答你的问题。

【讨论】:

    猜你喜欢
    • 2020-05-23
    • 2015-04-04
    • 2018-08-01
    • 2011-07-02
    • 2015-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多