如何在Django序列化器中编写带日期校验的update方法?
实现PersonHolidaysSerializer的update方法并复用校验逻辑
你可以把create方法里的校验逻辑抽成独立的公共方法,让create和update复用,避免代码重复。同时update时要排除当前正在更新的实例,防止把自身原有的假期日期误判为冲突。
以下是修改后的完整序列化器代码:
from django.db.models import Q from rest_framework import serializers from datetime import date, timedelta from .models import PersonHoliday class PersonHolidaysSerializer(serializers.ModelSerializer): person_name = serializers.ReadOnlyField() holiday_type_name = serializers.ReadOnlyField() person_full_name = serializers.ReadOnlyField( source="person.person_full_name") class Meta: model = PersonHoliday fields = '__all__' def get_date_ranges(self, start_date: date, end_date: date) -> list[date]: dt = (end_date - start_date).days return [start_date + timedelta(days=day) for day in range(dt+1)] def day_exists(self, values, requested_dates: list[date]) -> bool: delta_days_array = [] for value in values: existed_delta_days = self.get_date_ranges( value['holidays_start_date'], value['holidays_end_date'] ) delta_days_array.append(existed_delta_days) return any(x in y for x in requested_dates for y in delta_days_array) def _validate_holiday_data(self, validated_data, exclude_instance=None): """公共校验方法,供create和update复用""" person = validated_data.get('person') start_date = validated_data.get('holidays_start_date') end_date = validated_data.get('holidays_end_date') holiday_type = validated_data.get('holiday_type') # 日期顺序校验 if start_date > end_date: raise serializers.ValidationError("结束日期必须晚于开始日期") # 假期类型校验 if not holiday_type: raise serializers.ValidationError("必须选择假期类型") # 构建同用户的假期查询条件 query = Q( (Q(holidays_start_date__year=start_date.year) & Q(holidays_start_date__month=start_date.month)) | (Q(holidays_end_date__year=end_date.year) & Q(holidays_end_date__month=end_date.month)) ) & Q(person=person) # update操作时排除当前实例 if exclude_instance: query &= Q(pk__ne=exclude_instance.pk) instance_holiday = PersonHoliday.objects.filter(query) if instance_holiday.exists(): requested_delta_days = self.get_date_ranges(start_date, end_date) if self.day_exists(instance_holiday.values(), requested_delta_days): raise serializers.ValidationError("该时间段与已有假期冲突") def create(self, validated_data): self._validate_holiday_data(validated_data) return super().create(validated_data) def update(self, instance, validated_data): # 校验时排除当前实例,避免和自身原日期冲突 self._validate_holiday_data(validated_data, exclude_instance=instance) return super().update(instance, validated_data)
关键说明:
- 新增
_validate_holiday_data公共方法,将原create中的校验逻辑统一迁移至此,让两个方法共享校验规则,减少代码冗余。 - update方法调用校验时传入
exclude_instance=instance,查询已有假期时自动排除当前更新的记录,避免误判自身原日期为冲突。 - 调整基础校验(日期顺序、假期类型)的执行顺序,优先完成轻量校验,避免不必要的数据库查询。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

