Django中预设用户外键值并禁止修改、隐藏于Admin的实现方案
解决方案:无需第三方库实现自动赋值与Admin字段隐藏
一、调整模型定义
先移除django-currentuser相关依赖,将created_by和modified_by改为普通外键,后续通过Admin方法或模型信号自动赋值当前用户。
修改后的模型代码
from django.db import models from django.contrib.auth.models import User from django.utils import timezone from django.contrib.auth import get_user_model User = get_user_model() class Company(models.Model): created_by = models.ForeignKey(User, related_name='company_created_by', on_delete=models.CASCADE, blank=True, null=True) modified_by = models.ForeignKey(User, related_name='company_modified_by', on_delete=models.CASCADE, blank=True, null=True) created_date = models.DateTimeField(auto_now_add=True) modified_date = models.DateTimeField(auto_now=True) # 自动更新修改时间 name = models.CharField(max_length=150, unique=True) class Meta: verbose_name = "Company" verbose_name_plural = "Companies" def __str__(self): return self.name class UserProfile(models.Model): created_by = models.ForeignKey(User, related_name='userprofile_created_by', on_delete=models.CASCADE, blank=True, null=True) modified_by = models.ForeignKey(User, related_name='userprofile_modified_by', on_delete=models.CASCADE, blank=True, null=True) created_date = models.DateTimeField(auto_now_add=True) modified_date = models.DateTimeField(auto_now=True) def __str__(self): return f"Profile for {self.user.username}" # 可根据实际关联字段调整
二、自动赋值当前用户的两种方式
方式1:Admin层重写save_model(仅后台场景生效,简单直接)
在admin.py中配置模型管理类,重写save_model方法自动赋值,同时隐藏目标字段:
from django.contrib import admin from .models import Company, UserProfile @admin.register(Company) class CompanyAdmin(admin.ModelAdmin): list_display = ('name', 'created_by', 'modified_by', 'created_date', 'modified_date') # 列表页展示字段 exclude = ('created_by', 'modified_by') # 新增/编辑页隐藏字段 def save_model(self, request, obj, form, change): if not change: # 新建记录时设置创建人 obj.created_by = request.user obj.modified_by = request.user # 每次更新都设置修改人 super().save_model(request, obj, form, change) @admin.register(UserProfile) class UserProfileAdmin(admin.ModelAdmin): list_display = ('user', 'created_by', 'modified_by', 'created_date', 'modified_date') # 根据实际字段调整 exclude = ('created_by', 'modified_by') def save_model(self, request, obj, form, change): if not change: obj.created_by = request.user obj.modified_by = request.user super().save_model(request, obj, form, change)
方式2:模型信号(全局生效,适用于所有创建/更新场景)
如果需要在Admin以外的场景(如API、命令行)也自动赋值,可使用Django信号,同时借助中间件获取当前用户:
在模型文件末尾添加信号接收器:
from django.db.models.signals import pre_save from django.dispatch import receiver from django.contrib.auth.middleware import get_user from django.http import HttpRequest # 为Company绑定信号 @receiver(pre_save, sender=Company) def set_company_user(sender, instance, **kwargs): request = HttpRequest() user = get_user(request) if user.is_authenticated: if not instance.pk: # 新建记录 instance.created_by = user instance.modified_by = user # 更新记录 # 为UserProfile绑定信号 @receiver(pre_save, sender=UserProfile) def set_userprofile_user(sender, instance, **kwargs): request = HttpRequest() user = get_user(request) if user.is_authenticated: if not instance.pk: instance.created_by = user instance.modified_by = user
三、关键细节说明
modified_date用auto_now=True可自动更新修改时间,无需手动处理。- 若需在编辑页展示
created_by但禁止修改,可替换exclude为readonly_fields = ('created_by', 'modified_by'),并将字段加入fields或fieldsets配置。 - 信号方式需注意:命令行等非HTTP请求场景无用户上下文,需额外判断避免赋值失败。
内容的提问来源于stack exchange,提问作者Manza
相关产品推荐
相关产品推荐

