Python 在 post_save 信号中访问用户的请求
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4716330/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Accessing the user's request in a post_save signal
提问by Mo J. Mughrabi
I have done the below post_save signal in my project.
我在我的项目中完成了以下 post_save 信号。
from django.db.models.signals import post_save
from django.contrib.auth.models import User
# CORE - SIGNALS
# Core Signals will operate based on post
def after_save_handler_attr_audit_obj(sender, **kwargs):
print User.get_profile()
if hasattr(kwargs['instance'], 'audit_obj'):
if kwargs['created']:
kwargs['instance'].audit_obj.create(operation="INSERT", operation_by=**USER.ID**).save()
else:
kwargs['instance'].audit_obj.create(operation="UPDATE").save()
# Connect the handler with the post save signal - Django 1.2
post_save.connect(after_save_handler_attr_audit_obj, dispatch_uid="core.models.audit.new")
The operation_by column, I want to get the user_id and store it. Any idea how can do that?
operation_by 列,我想获取 user_id 并存储它。知道怎么做吗?
采纳答案by Ignacio Vazquez-Abrams
Can't be done. The current user is only available via the request, which is not available when using purely model functionality. Access the user in the view somehow.
做不到。当前用户只能通过请求获得,在使用纯模型功能时不可用。以某种方式访问视图中的用户。
回答by Filip Dupanovi?
Ignacio is right. Django's model signals are intended to notify other system components about events associated with instances and their respected data, so I guess it's valid that you cannot, say, access request data from a model post_savesignal, unless that request data was stored on or associated with the instance.
伊格纳西奥是对的。Django 的模型信号旨在通知其他系统组件有关与实例相关联的事件及其相关数据,因此我想您不能从模型post_save信号访问请求数据是有效的,除非该请求数据存储在实例。
I guess there are lots of ways to handle it, ranging from worse to better, but I'd say this is a primeexample for creating class-based/function-based generic views that will automatically handle this for you.
我想有很多方法可以处理它,从更糟到更好,但我想说这是创建基于类/基于函数的通用视图的一个主要示例,这些视图将自动为您处理。
Have your views that inherit from CreateView, UpdateViewor DeleteViewadditionally inherit from your AuditMixinclass if they handle verbs that operate on models that need to be audited. The AuditMixincan then hook into the views that successfully create\update\delete objects and create an entry in the database.
让您的视图继承自CreateView,UpdateView或者如果它们处理在需要审计的模型上运行的动词,则DeleteView另外继承自您的AuditMixin类。然后AuditMixin可以挂钩成功创建\更新\删除对象的视图并在数据库中创建一个条目。
Makes perfect sense, very clean, easily pluggable and gives birth to happy ponies. Flipside? You'll either have to be on the soon-to-be-released Django 1.3 release or you'll have to spend some time fiddlebending the function-based generic views and providing new ones for each auditing operation.
非常有意义,非常干净,易于插拔并生出快乐的小马。反面?您要么必须使用即将发布的 Django 1.3 版本,要么必须花一些时间来修改基于函数的通用视图并为每个审计操作提供新的视图。
回答by kiril
I imagine you would have figured this out, but I had the same problem and I realised that all the instances I create had a reference to the user that creates them(which is what you are looking for)
我想你会想到这一点,但我遇到了同样的问题,我意识到我创建的所有实例都有对创建它们的用户的引用(这就是你正在寻找的)
回答by Николай Сибилёв
context_processors.py
from django.core.cache import cache
def global_variables(request):
cache.set('user', request.user)
----------------------------------
in you model
from django.db.models.signals import pre_delete
from django.dispatch import receiver
from django.core.cache import cache
from news.models import News
@receiver(pre_delete, sender=News)
def news_delete(sender, instance, **kwargs):
user = cache.get('user')
in settings.py
TEMPLATE_CONTEXT_PROCESSORS = (
'web.context_processors.global_variables',
)
回答by PaulR
I was able to do it by inspecting the stack and looking for the view then looking at the local variables for the view to get the request. It feels like a bit of a hack, but it worked.
我能够通过检查堆栈并查找视图然后查看视图的局部变量以获取请求来做到这一点。感觉有点像黑客,但它奏效了。
import inspect, os
@receiver(post_save, sender=MyModel)
def get_user_in_signal(sender, **kwargs):
for entry in reversed(inspect.stack()):
if os.path.dirname(__file__) + '/views.py' == entry[1]:
try:
user = entry[0].f_locals['request'].user
except:
user = None
break
if user:
# do stuff with the user variable
回答by ALEXANDER GOMEZ HIGUITA
For traceability add two attributes to your Model(created_byand updated_by), in "updated_by" save the last user who modified the record. Then in your signal you have the user:
为了可追溯性,向您的模型(created_by和updated_by)添加两个属性,在“updated_by”中保存修改记录的最后一个用户。然后在你的信号中你有用户:
models.py:
模型.py:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
created_by = models. (max_length=100)
updated_by = models. (max_length=100)
views.py
视图.py
p = Question.objects.get(pk=1)
p.question_text = 'some new text'
p.updated_by = request.user
p.save()
signals.py
信号.py
@receiver(pre_save, sender=Question)
def do_something(sender, instance, **kwargs):
try:
obj = Question.objects.get(pk=instance.pk)
except sender.DoesNotExist:
pass
else:
if not obj.user == instance.user: # Field has changed
# do something
print('change: user, old=%s new=%s' % (obj.user, instance.user))
回答by firebird631
Why not adding a middleware with something like this :
为什么不添加这样的中间件:
class RequestMiddleware(object):
thread_local = threading.local()
def process_request(self, request):
RequestMiddleware.thread_local.current_user = request.user
and later in your code (specially in a signal in that topic) :
稍后在您的代码中(特别是在该主题中的信号中):
thread_local = RequestMiddleware.thread_local
if hasattr(thread_local, 'current_user'):
user = thread_local.current_user
else:
user = None
回答by bjorn
You could also use django-reversion for this purpose, e.g.
您也可以为此目的使用 django-reversion,例如
from reversion.signals import post_revision_commit
import reversion
@receiver(post_save)
def post_revision_commit(sender, **kwargs):
if reversion.is_active():
print(reversion.get_user())
Read more on their API https://django-reversion.readthedocs.io/en/stable/api.html#revision-api
阅读更多关于他们的 API https://django-reversion.readthedocs.io/en/stable/api.html#revision-api
回答by Yaroslav Varkhol
You can do a small hack by overriding you model save()method and setting the user on the saved instance as additional parameter. To get the user I used get_current_authenticated_user()from django_currentuser.middleware.ThreadLocalUserMiddleware(see https://pypi.org/project/django-currentuser/).
您可以通过覆盖模型save()方法并将保存的实例上的用户设置为附加参数来做一个小技巧。为了得到我所用的用户get_current_authenticated_user()从django_currentuser.middleware.ThreadLocalUserMiddleware(见https://pypi.org/project/django-currentuser/)。
In your models.py:
在您的models.py:
from django_currentuser.middleware import get_current_authenticated_user
class YourModel(models.Model):
...
...
def save(self, *args, **kwargs):
# Hack to pass the user to post save signal.
self.current_authenticated_user = get_current_authenticated_user()
super(YourModel, self).save(*args, **kwargs)
In your signals.py:
在您的signals.py:
@receiver(post_save, sender=YourModel)
def your_model_saved(sender, instance, **kwargs):
user = getattr(instance, 'current_authenticated_user', None)
PS: Don't forget to add 'django_currentuser.middleware.ThreadLocalUserMiddleware'to your MIDDLEWARE_CLASSES.
PS:不要忘记添加'django_currentuser.middleware.ThreadLocalUserMiddleware'到您的MIDDLEWARE_CLASSES.

