Mo *_*abi 34 python django signals
我在我的项目中完成了以下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")
Run Code Online (Sandbox Code Playgroud)
在operation_by列中,我想获取user_id并存储它.知道如何做到这一点?
Pau*_*ulR 14
我能够通过检查堆栈并查找视图,然后查看视图的局部变量来获取请求.这感觉有点像黑客,但它确实有效.
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
Run Code Online (Sandbox Code Playgroud)
小智 13
您可以借助中间件来做到这一点。在您的应用程序中创建get_request.py。然后
from threading import current_thread
from django.utils.deprecation import MiddlewareMixin
_requests = {}
def current_request():
return _requests.get(current_thread().ident, None)
class RequestMiddleware(MiddlewareMixin):
def process_request(self, request):
_requests[current_thread().ident] = request
def process_response(self, request, response):
# when response is ready, request should be flushed
_requests.pop(current_thread().ident, None)
return response
def process_exception(self, request, exception):
# if an exception has happened, request should be flushed too
_requests.pop(current_thread().ident, None)
Run Code Online (Sandbox Code Playgroud)
然后将此中间件添加到您的设置中:
MIDDLEWARE = [
....
'<your_app>.get_request.RequestMiddleware',
]
Run Code Online (Sandbox Code Playgroud)
然后将导入添加到您的信号中:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from <your_app>.get_request import current_request
# CORE - SIGNALS
# Core Signals will operate based on post
def after_save_handler_attr_audit_obj(sender, **kwargs):
print(Current User, current_request().user)
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")
Run Code Online (Sandbox Code Playgroud)
伊格纳西奥是对的.Django的模型信号旨在通知其他系统组件有关与实例相关的事件及其受尊重的数据,因此我认为您无法从模型post_save信号中访问请求数据,除非该请求数据存储在或与之关联.实例.
我想有很多方法可以处理它,从更糟到更好,但我会说这是创建基于类/基于函数的通用视图的一个主要示例,它将自动为您处理.
让你的观点,即继承CreateView,UpdateView或DeleteView另外从你的继承AuditMixin类,如果他们处理的是对需要审核模式操作的动词.然后,AuditMixin可以挂钩到成功创建\ update\delete对象的视图,并在数据库中创建一个条目.
具有完美的感觉,非常干净,易于插拔,并生出快乐的小马.另一面?您将要么必须处于即将发布的Django 1.3版本中,要么您将不得不花费一些时间来完成基于函数的通用视图并为每个审计操作提供新的视图.
为什么不添加这样的中间件:
class RequestMiddleware(object):
thread_local = threading.local()
def process_request(self, request):
RequestMiddleware.thread_local.current_user = request.user
Run Code Online (Sandbox Code Playgroud)
稍后在您的代码中(特别是在该主题中的信号中):
thread_local = RequestMiddleware.thread_local
if hasattr(thread_local, 'current_user'):
user = thread_local.current_user
else:
user = None
Run Code Online (Sandbox Code Playgroud)
小智 5
为了可追溯性,在模型(created_by和updated_by)中添加两个属性,在"updated_by"中保存修改记录的最后一个用户.然后在你的信号中你有用户:
models.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)
Run Code Online (Sandbox Code Playgroud)
views.py
p = Question.objects.get(pk=1)
p.question_text = 'some new text'
p.updated_by = request.user
p.save()
Run Code Online (Sandbox Code Playgroud)
signals.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))
Run Code Online (Sandbox Code Playgroud)
小智 5
你也可以为此目的使用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())
Run Code Online (Sandbox Code Playgroud)
阅读更多关于他们的API https://django-reversion.readthedocs.io/en/stable/api.html#revision-api