Django实现DB日期记录仅存单条 支持多次更新不新增条目
问题修复方案
核心问题原因
原有接口逻辑每次接收POST请求时,直接将传入数据传给序列化器执行save(),没有提前查询对应freeze_date的存量记录,因此每次请求都会触发数据库INSERT操作生成新条目。
修改步骤
1. 调整模型层,增加唯一约束
从数据库层面兜底保证同一个冻结日期仅存在一条记录,避免并发场景下出现重复数据,修改Models.py代码:
import datetime from django.db import models class FreezePrimaryCategory(models.Model): # 给freeze_date加unique=True约束,禁止同日期重复记录 freeze_date = models.DateField(default=datetime.datetime.now, unique=True) updated_date = models.DateTimeField(auto_now=True) def __str__(self) -> str: return str(self.freeze_date)
注意:添加该字段后需要执行
python manage.py makemigrations和python manage.py migrate同步数据库结构,如果库中已经存在重复的freeze_date记录,需要先手动清理重复数据再执行迁移,否则会报错。
2. 调整视图层逻辑,实现存在即更新、不存在则新建
修改Views.py的POST方法逻辑,提交时先查询对应freeze_date是否已有记录,有则传实例给序列化器走更新逻辑,无则走新建逻辑,同时保留原有权限、装饰器逻辑:
from rest_framework.views import APIView from rest_framework import status from rest_framework.response import Response from .models import FreezePrimaryCategory from .serializers import FreezeCategorySerializer # 保留原有IsAuthenticated、checkToken等导入不变 class FreezePrimaryCategory(APIView): permission_classes = (IsAuthenticated,) @checkToken def post(self, request): freeze_date = request.data.get("freeze_date") # 先查对应日期的存量记录 exist_instance = FreezePrimaryCategory.objects.filter(freeze_date=freeze_date).first() serializer = FreezeCategorySerializer( instance=exist_instance, data={"freeze_date": freeze_date} ) if serializer.is_valid(): serializer.save() # 新建返回201,更新返回200,符合REST接口规范 resp_status = status.HTTP_201_CREATED if exist_instance is None else status.HTTP_200_OK return Response(serializer.data, status=resp_status) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
3. 序列化器无需改动
原有Serializers.py的日期校验逻辑完全兼容新逻辑,不管是新建还是更新场景,序列化器都会自动执行validate方法做日期合法性判断;模型层的updated_date字段配置了auto_now=True,每次执行save()都会自动更新为当前时间,完全符合需求,原有代码保留即可:
from datetime import date from rest_framework import serializers from .models import FreezePrimaryCategory class FreezeCategorySerializer(serializers.ModelSerializer): class Meta: model = FreezePrimaryCategory fields = ['freeze_date'] def validate(self, data): today = date.today() if data['freeze_date'] >= today: raise serializers.ValidationError('Date cannot be greater than current Date') return data
效果验证
- 首次提交未入库的
freeze_date:正常新建记录,返回201状态码,updated_date自动生成 - 重复提交相同
freeze_date:直接更新原有记录,不生成新条目,updated_date自动刷新为本次请求时间 - 提交大于等于当日的日期:正常触发校验返回400错误,原有校验逻辑不受影响
内容的提问来源于stack exchange,提问作者deepak
相关产品推荐
相关产品推荐

