Get current user log in signal in Django

后端 未结 6 1767
忘掉有多难
忘掉有多难 2021-02-05 10:01

I am just using the admin site in Django. I have 2 Django signals (pre_save and post_save). I would like to have the username of the current user. How would I do that? It does n

相关标签:
6条回答
  • 2021-02-05 10:16

    You can use a middleware to store the current user: http://djangosnippets.org/snippets/2179/

    Then you would be able to get the user with get_current_user()

    0 讨论(0)
  • 2021-02-05 10:20

    In both signals, signal send three arguments,

    • Sender
    • Instance
    • Using

    What you need is the Instant being modified...

    def signal_catcher(sender, instance, **kwargs):
        uname = instance.username
    

    http://docs.djangoproject.com/en/dev/ref/signals/#pre-save

    0 讨论(0)
  • 2021-02-05 10:22

    Being reluctant to mess around with thread-local state, I decided to try a different approach. As far as I can tell, the post_save and pre_save signal handlers are called synchronously in the thread that calls save(). If we are in the normal request handling loop, then we can just walk up the stack to find the request object as a local variable somewhere. e.g.

    from django.db.models.signals import pre_save
    from django.dispatch import receiver
    
    @receiver(pre_save)
    def my_callback(sender, **kwargs):
        import inspect
        for frame_record in inspect.stack():
            if frame_record[3]=='get_response':
                request = frame_record[0].f_locals['request']
                break
        else:
            request = None
        ...
    

    If there's a current request, you can grab the user attribute from it.

    Note: like it says in the inspect module docs,

    This function relies on Python stack frame support in the interpreter, which isn’t guaranteed to exist in all implementations of Python.

    0 讨论(0)
  • 2021-02-05 10:23

    If you are using the admin site why not use a custom model admin

    class MyModelAdmin( admin.ModelAdmin ):
        def save_model( self, request, obj, form, change ):
            #pre save stuff here
            obj.save()
            #post save stuff here
    
    
    
    admin.site.register( MyModel, MyModelAdmin )
    

    A signal is something that is fired every time the object is saved regardless of if it is being done by the admin or some process that isn't tied to a request and isn't really an appropriate place to be doing request based actions

    0 讨论(0)
  • 2021-02-05 10:29

    We can solve this problem using middleware classes. Create singleton class in where will be storing user variable.

    class Singleton(type):
        '''
            Singleton pattern requires for GetUser class
        '''
        def __init__(cls, name, bases, dicts):
            cls.instance = None
    
        def __call__(cls, *args, **kwargs):
            if cls.instance is None:
                cls.instance = super(Singleton, cls).__call__(*args, **kwargs)
            return cls.instance 
    
    
    class NotLoggedInUserException(Exception):
        '''
        '''
        def __init__(self, val='No users have been logged in'):
            self.val = val
            super(NotLoggedInUser, self).__init__()
    
        def __str__(self):
            return self.val
    
    class LoggedInUser(object):
        __metaclass__ = Singleton
    
        user = None
    
        def set_user(self, request):
            if request.user.is_authenticated():
                self.user = request.user
    
        @property
        def current_user(self):
            '''
                Return current user or raise Exception
            '''
            if self.user is None:
                raise NotLoggedInUserException()
            return self.user
    
        @property
        def have_user(self):
        return not user is None
    

    Create own middleware class that will be setting user for LoggedInUser instance,and insert out middleware after 'django.contrib.auth.middleware.AuthenticationMiddleware' in settings.py

    from useranytimeaccess import LoggedInUser
    class LoggedInUserMiddleware(object):
        '''
            Insert this middleware after django.contrib.auth.middleware.AuthenticationMiddleware
        '''
        def process_request(self, request):
            '''
                Returned None for continue request
            '''
            logged_in_user = LoggedInUser()
            logged_in_user.set_user(request)
            return None
    

    In signals import LoggedInUser class and get current user

    logged_in = LoggedInUser()
    user = logged_in.user
    
    0 讨论(0)
  • 2021-02-05 10:35

    Without hack: use signals when user logs in / out to remember who is logged, and for the Django test framework, as long as you connect and it calls the signals, this will work too:

    current_user = None
    
    @receiver(user_logged_in, sender=User)
    def user_logged_in(sender, request, user, **kwargs):
        global current_user
        current_user = user
    
    @receiver(user_logged_out, sender=User)
    def user_logged_out(sender, request, user, **kwargs):
        global current_user
        current_user = None
    
    @receiver(post_save, sender=StatusHistory)
    def status_history_post_save(sender, instance: StatusHistory,
                                 created, **kwargs):
        global current_user
        if current_user is None or instance is None or instance.shipment is None:
            return
        # ok if we here -> user is connected, keep on:
        # .........
        # blabla
        # .........
    
    0 讨论(0)
提交回复
热议问题