在post_save信号中访问用户请求

56 投票
13 回答
46390 浏览
提问于 2025-04-16 10:07

我在我的项目中做了一个叫做 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")

在 operation_by 这一列中,我想获取用户的 ID 并把它存起来。有没有什么办法可以做到这一点?

13 个回答

10

我通过查看堆栈来找到视图,然后查看这个视图的局部变量,以获取请求信息。虽然这有点像是变通的方法,但确实有效。

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
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)

接下来,把这个中间件添加到你的设置里:

MIDDLEWARE = [
    ....
    '<your_app>.get_request.RequestMiddleware',
]

然后在你的信号中添加导入:

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")
41

这件事做不了。因为当前用户的信息只能通过请求来获取,而在单纯使用模型功能的时候,这个请求是无法得到的。你需要在视图中以某种方式来访问用户的信息。

撰写回答