Django中pre_save信号无法阻止用户24小时内创建多个Mining对象
问题分析与解决方案
你的核心问题出在新对象的判断逻辑错误,以及可能存在的信号未正确注册问题,以下是分步解决办法:
1. 修正信号中的新对象判断逻辑
你的Mining模型使用UUID作为主键,且设置了default=uuid.uuid4,这意味着实例化新对象时instance.pk已经生成了UUID值,导致if not instance.pk条件永远为False,限制逻辑根本不会执行。
Django提供了更可靠的判断方式:使用instance._state.adding属性,这是Django内部标记实例是否待新增到数据库的布尔值。
修正后的信号代码:
from django.db.models.signals import pre_save from django.dispatch import receiver from django.utils import timezone from datetime import timedelta from django.core.exceptions import ValidationError from .models import Mining @receiver(pre_save, sender=Mining) def prevent_multiple_mining_per_day(sender, instance, **kwargs): # 使用_state.adding判断是否为新建对象 if instance._state.adding: last_24_hours = timezone.now() - timedelta(hours=24) has_recent = Mining.objects.filter( user=instance.user, created_at__gte=last_24_hours ).exists() if has_recent: raise ValidationError("User has already mined in the last 24 hours.")
2. 确保信号已正确注册
Django不会自动发现信号文件,需确保信号模块被加载:
- 方法一:在app的
models.py末尾添加导入语句:from . import signals - 方法二:在app的
apps.py中重写ready()方法(推荐):
同时在from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'your_app_name' def ready(self): import your_app_name.signalssettings.py的INSTALLED_APPS中用配置类注册app:INSTALLED_APPS = [ # ... 'your_app_name.apps.YourAppConfig', # ... ]
3. 检查Admin的save_model实现
如果自定义了MiningAdmin的save_model方法,必须调用父类方法,否则会跳过默认save流程,导致信号不触发:
from django.contrib import admin from .models import Mining class MiningAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): # 必须调用父类方法以触发信号 super().save_model(request, obj, form, change) admin.site.register(Mining, MiningAdmin)
内容的提问来源于stack exchange,提问作者Memon
相关产品推荐
相关产品推荐

