
本文介绍如何在 Django 后台管理界面中,于模型首次保存时自动将当前登录用户写入 added_by 字段,关键在于重写 ModelAdmin.save_model() 方法并正确判断新增状态。
本文介绍如何在 django 后台管理界面中,于模型首次保存时自动将当前登录用户写入 `added_by` 字段,关键在于重写 `modeladmin.save_model()` 方法并正确判断新增状态。
在 Django Admin 中实现“记录创建者”功能是一个常见需求,但容易误将逻辑放在模型(Model)层——这会导致 request 对象不可用(因为模型本身不感知 HTTP 请求),从而出现 request.user 为匿名用户或 None 的问题。
正确的做法是将该逻辑置于 ModelAdmin 子类中,利用其 save_model() 钩子方法。该方法在 Admin 保存对象时被调用,并显式接收 request 参数,确保可安全访问当前登录用户。
✅ 正确实现步骤
-
定义模型字段(保持简洁、符合规范):
# models.py from django.conf import settings from django.db import models
class Project(models.Model): name = models.CharField(max_length=200)
其他字段...
added_by = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.PROTECT,
null=True,
blank=True,
editable=False, # Admin 中隐藏该字段,避免手动修改
related_name='created_projects'
)> ? 建议添加 `editable=False` 并配合 `related_name`,既防止后台误编辑,也便于反向查询(如 `user.created_projects.all()`)。
2. **注册 ModelAdmin 并重写 `save_model`**:
```python
# admin.py
from django.contrib import admin
from .models import Project
@admin.register(Project)
class ProjectAdmin(admin.ModelAdmin):
list_display = ('name', 'added_by', 'created_at') # 可选:展示创建者
readonly_fields = ('added_by',) # 可选:在编辑页显示只读信息
def save_model(self, request, obj, form, change):
# 使用 obj._state.adding 判断是否为新建实例(更可靠 than not obj.pk)
if obj._state.adding:
obj.added_by = request.user
super().save_model(request, obj, form, change)⚠️ 注意事项与最佳实践
- 不要在模型 save() 方法中使用 request:模型层无请求上下文,强行传入 request 会破坏分层设计,且导致单元测试困难。
-
优先使用 obj._state.adding 而非 not obj.pk:
obj._state.adding 是 Django 官方推荐方式,能准确标识“即将执行 INSERT”,而 not obj.pk 在某些场景(如 UUID 主键未赋值、bulk_create)下可能失效。 - 权限与数据一致性:若需限制仅特定用户可创建/修改 added_by,应在 get_form() 或 has_add_permission() 中补充校验,而非依赖前端隐藏。
- 时间戳建议同步添加:通常与 added_by 配套使用 created_at = models.DateTimeField(auto_now_add=True),增强审计能力。
✅ 验证效果
登录 Admin(如 superuser),新建一个 Project 实例并提交。查看数据库或 Admin 列表页,added_by 字段将自动填充为当前登录用户,且无法在编辑页被更改(因设为 readonly_fields 或 editable=False)。
通过这一模式,你可在不侵入业务模型的前提下,稳健、可维护地实现操作审计与责任追溯。









