You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django DRF如何拦截已存在同医生预约数据的POST提交请求

解决方案

现有代码问题梳理

  • 模型缩进错误:Appointment 类现在缩进在Patient类内部,属于嵌套类,无法正常关联使用,需要先把它移到和Doctor、Patient同级的位置
  • 视图逻辑错误:AppointmentDetailAPI的post方法中,patient_name = Patient.objects.all()和doctor_name = Doctor.objects.all()获取了全量患者和医生数据,没有读取请求提交的目标医生、预约时间参数,无法做冲突校验
  • 视图类选型错误:AppointmentCreateAPI继承的是RetrieveUpdateDestroyAPIView,仅支持查询、更新、删除操作,不支持创建预约的POST请求
  • 缺少冲突校验逻辑:没有判断目标医生在指定时间是否已有生效预约

修复步骤

1. 修正模型缩进

把Appointment类移动到Patient类外部,和Doctor、Patient平级,这一步是后续逻辑正常运行的基础。

2. 序列化器增加预约冲突校验(推荐在序列化层做校验,复用性更高)

修改serializers.py中的AppointmentSerializer:

class AppointmentSerializer(serializers.ModelSerializer):
    """
    Appointment serializer class
    """

    class Meta:
        model = Appointment
        fields = "__all__"
    
    def validate(self, attrs):
        # 校验目标医生在指定时间是否已有生效预约
        is_exist = Appointment.objects.filter(
            doctor_name=attrs['doctor_name'],
            appointment_date=attrs['appointment_date'],
            active=True
        ).exists()
        if is_exist:
            raise serializers.ValidationError("该医生当前时间已有排期,无法预约")
        return attrs

如果你是按时间段预约(比如单条预约占30分钟),可以把时间判断逻辑改成时间区间重叠判断,示例:

from datetime import timedelta
# 假设单条预约时长30分钟
appoint_start = attrs['appointment_date']
appoint_end = appoint_start + timedelta(minutes=30)
is_exist = Appointment.objects.filter(
    doctor_name=attrs['doctor_name'],
    active=True,
    appointment_date__lt=appoint_end,
    appointment_date__gte=appoint_start
).exists()

3. 修正视图逻辑

你可以直接把创建功能整合到AppointmentDetailAPI的post方法中,修改views.py的对应代码:

class AppointmentDetailAPI(APIView):
    def get(self, request):
        appointment = Appointment.objects.all()
        serializer = AppointmentSerializer(appointment, many=True)
        return Response(serializer.data)

    def post(self, request):
        serializer = AppointmentSerializer(data=request.data)
        # 序列化器会自动执行我们上面加的冲突校验
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)

如果需要单独的创建接口,也可以把AppointmentCreateAPI改成支持创建的视图类:

class AppointmentCreateAPI(generics.CreateAPIView):
    queryset = Appointment.objects.all()
    serializer_class = AppointmentSerializer

内容的提问来源于stack exchange,提问作者Dubey Ravi vinod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 07:39:04