You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:04:14