如何在Django Admin中获取修改内联模型的用户ID并记录AuditLog?
解决Django Inline Formset保存时记录操作用户到AuditLog的问题
我之前也碰到过这个一模一样的问题——Django的BaseInlineFormSet确实没直接提供获取当前用户的途径,但其实通过自定义Inline和FormSet的组合就能完美解决,而且逻辑很清晰。核心思路是把Admin页面的当前请求用户传递给Inline FormSet,然后在FormSet的保存流程中记录AuditLog。
步骤1:自定义Inline FormSet,添加用户支持
首先我们要写一个继承自BaseInlineFormSet的自定义类,它能接收并存储当前用户,然后在保存对象时生成AuditLog。这里我们可以利用FormSet自带的new_objects、changed_objects、deleted_objects属性来覆盖所有操作场景:
from django.forms.models import BaseInlineFormSet from .models import AuditLog # 假设你已经定义了AuditLog模型 class BookInlineFormSet(BaseInlineFormSet): def __init__(self, *args, **kwargs): # 从初始化参数中取出用户,保存为实例属性 self.current_user = kwargs.pop('user', None) super().__init__(*args, **kwargs) def save(self, commit=True): # 先执行父类的save逻辑,拿到待处理的对象列表 saved_objs = super().save(commit=False) # 1. 记录新增的Book对象 for obj in self.new_objects: if self.current_user and commit: AuditLog.objects.create( content_object=obj, action="CREATE", user=self.current_user, # 可以添加其他字段,比如操作时间(默认auto_now_add) ) if commit: obj.save() # 2. 记录修改的Book对象 for instance, changed_fields in self.changed_objects: if self.current_user and commit and changed_fields: AuditLog.objects.create( content_object=instance, action="UPDATE", user=self.current_user, changed_fields=", ".join(changed_fields) # 记录修改的字段 ) if commit: instance.save() # 3. 记录删除的Book对象 for obj in self.deleted_objects: if self.current_user and commit: AuditLog.objects.create( content_object=obj, action="DELETE", user=self.current_user, ) if commit: obj.delete() # 处理多对多关系(如果Book模型有相关字段的话) if commit: self.save_m2m() return saved_objs
步骤2:自定义InlineAdmin,传递当前用户到FormSet
接下来我们要写一个自定义的Inline类,重写get_formset方法,把Admin页面的当前请求用户传递给上面的FormSet:
from django.contrib import admin from .models import Book class BookInline(admin.TabularInline): # 用StackedInline也可以,根据你的需求 model = Book formset = BookInlineFormSet def get_formset(self, request, obj=None, **kwargs): # 动态生成一个绑定了当前用户的FormSet子类 class UserBoundBookFormSet(self.formset): def __init__(self, *args, **kwargs): # 把当前请求的用户传入FormSet的初始化参数 kwargs['user'] = request.user super().__init__(*args, **kwargs) # 替换原有的formset为我们动态生成的子类 kwargs['formset'] = UserBoundBookFormSet return super().get_formset(request, obj, **kwargs)
步骤3:把Inline加到AuthorAdmin中
最后把这个自定义的Inline注册到你的AuthorAdmin里就可以了:
from django.contrib import admin from .models import Author @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): inlines = [BookInline] # 其他Admin配置...
额外注意事项
- 确保你的
AuditLog模型支持GenericForeignKey(如果需要关联多个模型的话),示例模型大概是这样:from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.auth import get_user_model User = get_user_model() class AuditLog(models.Model): action = models.CharField(max_length=10, choices=[("CREATE", "创建"), ("UPDATE", "更新"), ("DELETE", "删除")]) user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) object_id = models.PositiveIntegerField() content_object = GenericForeignKey("content_type", "object_id") changed_fields = models.TextField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ["-created_at"] - 如果不需要记录删除或更新操作,可以直接去掉对应的代码块,简化逻辑
- 测试时要验证:在Author编辑页面添加/修改/删除Book后,AuditLog中是否正确生成了记录,并且关联了当前登录的用户
内容的提问来源于stack exchange,提问作者minder
相关产品推荐
相关产品推荐

