Django模型save()方法如何获取request.user 或在视图中拿到生成的随机密码
解决方案
以下提供两种可行实现思路,同时会修正原代码中存在的明文存储密码的潜在问题。
方案1:传递request到save方法
Django模型层默认不持有请求上下文,你可以手动将request作为自定义参数传入save方法:
修改save方法
def save(self, *args, request=None, **kwargs): if self._state.adding: super(Machine, self).save(*args, **kwargs) username = f"machine_{slugify(self.site.client.name).lower()}_{self.id}" password = User.objects.make_random_password() # 注意:不要用create,要用create_user才会自动对密码做哈希处理 self.user = User.objects.create_user( username=username, password=password ) # 将生成的密码存为实例临时属性,方便外部调用时获取 self.generated_password = password super(Machine, self).save(update_fields=['user']) # 传入了request才执行发邮件逻辑 if request: send_mail( f'Password of {username}', f'Password: {password}', settings.DEFAULT_FROM_EMAIL, [request.user.email], fail_silently=True, ) else: super(Machine, self).save(*args, **kwargs)
视图/Admin中调用时传参
- 普通视图调用示例:
# 视图层创建实例时传入当前request machine = Machine(字段名=字段值) machine.save(request=request) # 直接从实例属性获取生成的随机密码 pwd = machine.generated_password
- 如果你使用Django Admin操作,需要重写Admin类的save_model方法传递request:
from django.contrib import admin from .models import Machine class MachineAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.save(request=request) admin.site.register(Machine, MachineAdmin)
方案2:抽离业务逻辑到模型层外(更推荐)
Django设计原则中模型层本就应该和请求上下文解耦,把创建关联用户、发邮件的逻辑从save方法中抽离到视图层/服务层,耦合性更低、后续维护更方便:
简化模型save方法
def save(self, *args, **kwargs): super().save(*args, **kwargs)
视图层实现完整业务逻辑
def create_machine(request): # 1. 创建Machine实例 machine = Machine( site=你的site实例, # 其他字段填充 ) machine.save() # 2. 生成关联用户 username = f"machine_{slugify(machine.site.client.name).lower()}_{machine.id}" password = User.objects.make_random_password() machine.user = User.objects.create_user(username=username, password=password) machine.save(update_fields=['user']) # 3. 直接在视图层发邮件,无需传递request send_mail( f'Password of {username}', f'Password: {password}', settings.DEFAULT_FROM_EMAIL, [request.user.email], fail_silently=True, ) # 可直接获取密码做其他业务处理 return HttpResponse(f"实例创建完成,关联用户密码为:{password}")
重要提醒:原代码中直接使用
User.objects.create传入password参数会导致密码明文存储在数据库中,既不符合安全要求也会导致后续用户无法正常登录,必须替换为User.objects.create_user方法。
内容的提问来源于stack exchange,提问作者darkvodka
相关产品推荐
相关产品推荐

