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

Django中如何阻止添加日期重复的公休假日?现有代码失效求解

问题原因

你遇到的问题核心是序列化器验证用的是原始提交日期,但pre_save信号会把日期替换成当前年份的同月同日,导致验证时查询的日期和最终存入数据库的日期不是同一个,自然检测不到重复。

比如你提交2023-10-01,验证时查的是2023-10-01,但信号会改成2024-10-01(假设当前是2024年),如果数据库里已经有2024-10-01,验证时根本查不到,就会跳过验证直接保存,最终导致重复。

解决步骤

1. 统一验证和信号处理的日期逻辑

把信号里的日期转换逻辑抽成工具函数,让序列化器验证时也用转换后的日期查询,确保验证和保存用的是同一个日期:

先添加工具函数:

from django.utils import timezone

def get_current_year_date(date):
    return date.replace(year=timezone.now().year)

修改pre_save信号:

@receiver(pre_save, sender=PublicHoliday)
def save_current_year(sender, instance, **kwargs):
    instance.date_time = get_current_year_date(instance.date_time)

修改序列化器的验证逻辑,用转换后的日期检查:

class PublicHolidayCreateSerializer(serializers.ModelSerializer):
    class Meta:
        model = PublicHoliday
        fields = '__all__'

    def validate_date_time(self, value):
        # 先把日期转换成当前年份的日期
        current_year_date = get_current_year_date(value)
        # 创建时检查重复
        if self.instance is None:
            if PublicHoliday.objects.filter(date_time=current_year_date).exists():
                raise serializers.ValidationError("This public day already exists")
        # 更新时排除自身检查重复
        else:
            if PublicHoliday.objects.filter(date_time=current_year_date).exclude(pk=self.instance.pk).exists():
                raise serializers.ValidationError("This public day already exists")
        return value

    def create(self, validated_data):
        return super().create(validated_data)
    
    def update(self, instance, validated_data):
        return super().update(instance, validated_data)

2. 模型层添加唯一约束(必做)

只在序列化器做验证有并发风险,比如两个请求同时提交相同日期,序列化器验证都通过,但保存时会出现重复。所以要在模型层给date_time加唯一约束:

class PublicHoliday(models.Model):
    name = models.CharField(_('Holiday Name'), max_length=100, unique=True)
    date_time = models.DateField(_('Holiday Date'), unique=True)  # 添加unique=True
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self) -> str:
        return self.name

# 信号部分不变

加完后执行迁移:

python manage.py makemigrations
python manage.py migrate

3. 捕获模型层唯一约束异常(可选)

模型层的唯一约束会抛出IntegrityError,可以在序列化器里捕获这个异常,转换成友好的验证错误:

from django.db import IntegrityError

class PublicHolidayCreateSerializer(serializers.ModelSerializer):
    # 其他代码不变

    def create(self, validated_data):
        try:
            return super().create(validated_data)
        except IntegrityError:
            raise serializers.ValidationError("This public day already exists")
    
    def update(self, instance, validated_data):
        try:
            return super().update(instance, validated_data)
        except IntegrityError:
            raise serializers.ValidationError("This public day already exists")
总结
  1. 用统一的日期转换函数,解决验证逻辑和实际保存日期不一致的问题;
  2. 模型层加唯一约束,从根本上防止重复数据;
  3. 捕获模型层异常,返回友好的错误信息。

内容的提问来源于stack exchange,提问作者Mike

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 20:05:16