如何限制Django模型对象24小时内仅能创建一次?
实现Django模型对象的创建频率限制
针对你的需求,分两种场景给出实现方案:
一、自然日(当日0-24点)内仅允许创建一次(用unique_for_date)
首先你的模型需要关联用户(否则无法针对单个用户做限制),修改模型如下:
from django.contrib.auth.models import User from django.db import models class MyModel(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE, unique_for_date='created_at') created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) deleted_at = models.DateTimeField(null=True, blank=True) def __str__(self): return f"{self.user.username} - {self.created_at}"
这里unique_for_date='created_at'的作用是:同一个用户在created_at对应的自然日(年月日)内,只能创建一条MyModel记录。Django会在模型验证和数据库层面(自动创建唯一索引)保证这个约束。
错误提示处理
当用户尝试重复创建时,Django会抛出IntegrityError,你可以在视图中捕获并返回友好提示:
from django.db import IntegrityError from django.shortcuts import render, redirect from .models import MyModel def create_mymodel(request): if request.method == 'POST': try: MyModel.objects.create(user=request.user) return redirect('success_page') except IntegrityError: return render(request, 'create_form.html', {'error': '你今日已经创建过该记录,无法重复操作'}) return render(request, 'create_form.html')
如果使用表单类,也可以在表单的clean方法中提前验证:
from django import forms from .models import MyModel from django.utils import timezone class MyModelForm(forms.ModelForm): class Meta: model = MyModel fields = [] # user和created_at自动赋值,无需用户输入 def clean(self): cleaned_data = super().clean() user = self.request.user today = timezone.now().date() if MyModel.objects.filter(user=user, created_at__date=today).exists(): raise forms.ValidationError('你今日已经创建过该记录,无法重复操作') return cleaned_data
二、任意24小时窗口内仅允许创建一次(自定义验证)
如果你的需求是从上次创建时间起算,滚动24小时内不能再次创建(而非固定自然日),unique_for_date无法满足,需要自定义验证逻辑:
1. 模型层验证
在模型中添加clean方法,在保存前做校验:
from django.db import models from django.contrib.auth.models import User from django.utils import timezone from django.core.exceptions import ValidationError class MyModel(models.Model): user = models.ForeignKey(User, on_delete=models.CASCADE) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) deleted_at = models.DateTimeField(null=True, blank=True) def clean(self): super().clean() # 检查当前用户过去24小时内是否已有记录 twenty_four_hours_ago = timezone.now() - timezone.timedelta(hours=24) if MyModel.objects.filter(user=self.user, created_at__gte=twenty_four_hours_ago).exists(): raise ValidationError('你在24小时内已经创建过该记录,请稍后再试') def save(self, *args, **kwargs): self.full_clean() # 强制执行验证逻辑 super().save(*args, **kwargs)
2. 错误提示处理
在视图中捕获验证错误并返回提示:
from django.core.exceptions import ValidationError from django.shortcuts import render, redirect from .models import MyModel def create_mymodel(request): if request.method == 'POST': try: MyModel.objects.create(user=request.user) return redirect('success_page') except ValidationError as e: return render(request, 'create_form.html', {'error': e.message}) return render(request, 'create_form.html')
注意:模型层的clean方法不会在bulk_create批量创建时自动执行,若有批量操作场景需要手动调用验证;高并发场景下可考虑添加数据库事务或锁来避免竞态条件。
内容的提问来源于stack exchange,提问作者Mehdi Aria
相关产品推荐
相关产品推荐

