如何在Django Admin中实现类似nowait=True的锁冲突即时报错?
Django Admin实现nowait=True避免锁等待
要在Django Admin中实现编辑锁定条目时直接报错,核心是在获取待编辑对象时加上select_for_update(nowait=True),并捕获锁冲突异常后返回友好提示。
实现步骤
1. 自定义ModelAdmin类,重写get_object方法
Admin页面编辑对象时会调用get_object获取目标实例,我们需要在这里修改查询逻辑,加入行级锁的nowait参数:
from django.contrib import admin from django.db import DatabaseError, OperationalError from django.core.exceptions import ValidationError from django.db import connection from .models import MyModel # 替换成你的模型类 class MyModelAdmin(admin.ModelAdmin): def get_object(self, request, object_id, from_field=None): queryset = self.get_queryset(request) try: # 使用select_for_update(nowait=True)查询,锁冲突时直接抛出异常 return queryset.select_for_update(nowait=True).get(pk=object_id) except (DatabaseError, OperationalError) as e: # 根据数据库类型判断锁冲突异常 lock_error = False if connection.vendor == 'postgresql': # PostgreSQL锁不可用的错误码是55P03 if hasattr(e, 'pgcode') and e.pgcode == '55P03': lock_error = True elif connection.vendor == 'mysql': # MySQL锁超时的错误码是1205 if len(e.args) > 0 and e.args[0] == 1205: lock_error = True elif connection.vendor == 'sqlite': # SQLite的锁异常信息包含"database is locked" if 'database is locked' in str(e): lock_error = True if lock_error: raise ValidationError("database entry is locked") # 非锁异常直接重新抛出 raise # 注册模型与自定义Admin admin.site.register(MyModel, MyModelAdmin)
2. 异常处理说明
不同数据库的锁冲突异常表现不同,上面的代码针对主流数据库做了适配:
- PostgreSQL:通过
pgcode判断55P03(锁不可用) - MySQL:通过错误码
1205(锁等待超时) - SQLite:通过异常信息中的"database is locked"判断
3. 效果验证
当你的脚本通过select for update锁定条目后,在Admin页面尝试编辑该条目时,会立即在页面顶部显示"database entry is locked"的错误提示,不会再等待锁释放。
内容的提问来源于stack exchange,提问作者Goroshek
相关产品推荐
相关产品推荐

