简体   繁体   English

如何在模型中的 def save() 中访问 request.user?

[英]How to access to request.user in def save() in models?

I want to create a user at the creation of an object.我想在创建对象时创建一个用户。 This object is linked to the user by a foreign key.该对象通过外键链接到用户。 I have override the def_save() method to create the user and link it to the object.我已经覆盖了 def_save() 方法来创建用户并将其链接到对象。

Problem: I generate a random password for this user and I would like to send it by e-mail not to the just created user but to the user.问题:我为这个用户生成了一个随机密码,我想通过电子邮件将它发送给用户而不是刚刚创建的用户。

    def save(self, *args, **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()
            self.user = User.objects.create(
                username=username,
                password=password
            )
            
            self.save(update_fields=['user'])

            send_mail(
                f'Password of {username}',
                f'Password: {password}',
                settings.DEFAULT_FROM_EMAIL,
                [self.request.user.email],
                fail_silently=True,
            )
        else:
            super(Machine, self).save(*args, **kwargs)

The problem is that I don't have access to self.request in this method.问题是我无法在此方法中访问self.request How can I access to request in my def save()?如何在我的 def save() 中访问request

Or how can I get the password value in my view?或者如何在我的视图中获取密码值?

I think you should design this differently.我认为你应该以不同的方式设计它。

If there is always a view, it suggests that the only legitimate place this object and the related user could be created is inside a particular view.如果始终存在视图,则表明可以创建此对象和相关用户的唯一合法位置是在特定视图内。 So, use get_or_create and if it was created, then invoke the logic to create and associate the new user and e-mail the password to the current Django user.因此,使用get_or_create并且如果它已创建,则调用逻辑来创建和关联新用户,并将密码通过电子邮件发送给当前 Django 用户。

You could harden it against object creation outside of an appropriate view by instead using您可以通过使用

try:
    existing_instance = MyModel.objects.get( ...)
except MyModel.DoesNotExist
    new = MyModel( ...)
    # create and associate the User object here

    setattr( new, '_foo_bar', 'not_Molly')   # a Mollyguard
    new.save()

and check in MyModel's save method that self._foo_bar is present and correct.并在 MyModel 的保存方法中self._foo_bar是否存在且正确。 Raise a meaningful error if not.如果没有,则提出一个有意义的错误。 This will avoid accidental creation of MyModel instances without an associated User by, say, newly recruited help who don't fully understand the bad implications of doing this.这将避免在没有关联用户的情况下意外创建 MyModel 实例,例如,新招募的帮助不完全了解这样做的不良影响。

If you really, really want, you could pass the current request.User as the value of an attribute, and check isinstance( self._foo_bar, User) and then having crashed out if you don't have a valid User, put the logic in the save method.如果你真的真的想要,你可以将当前的request.User作为属性的值传递,并检查isinstance( self._foo_bar, User)如果你没有有效的用户,然后崩溃,把逻辑在保存方法中。 This feels wrong to me.这对我来说是错误的。

To answer your question directly (I definitely think you should read the design suggestions here also) but to get the request object throughout the request cycle, one solution is threadlocals .要直接回答您的问题(我绝对认为您也应该在这里阅读设计建议)但要在整个请求周期中获取请求对象,一种解决方案是threadlocals Threadlocals middleware puts the request object on a thread-accessible storage, and then provides a get_current_request handler that you can import anywhere and grab the request off of local storage. Threadlocals 中间件将请求对象放在线程可访问的存储上,然后提供一个 get_current_request 处理程序,您可以将其导入任何地方并从本地存储中获取请求。

So many caveats here: Django core devs intentionally didn't include this functionality, here is a great discussion of why you shouldn't do this, Python is not 100% thread safe, this may be (and probably is) an anti-pattern, and consider the cases brought up in this thread.这里有很多警告:Django 核心开发人员故意不包含此功能,这里有一个很好的讨论,说明为什么不应该这样做,Python 不是 100% 线程安全的,这可能是(并且可能是)反模式,并考虑在此线程中提出的案例。

I don't think that save_model method override is the best option.我不认为 save_model 方法覆盖是最好的选择。 Imagine, for instance, that you want to save the user info or validate the model based on user info and that save() does not come from a view or the adminsite itself.想象一下,例如,您想要保存用户信息或根据用户信息验证模型,而 save() 不是来自视图或管理站点本身。

What people are asking are constructions like those one:人们问的是像这样的结构:

def save(..)
    self.user = current_user()

or或者

def save(..)
    user = current_user()
    if user.group == 'XPTO':
        error('This user cannot edit this record')

The best approach I found so far is:到目前为止,我发现的最佳方法是:

here这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM