2011-01-18 2 views
10

Я просто использую сайт admin в Django. У меня есть 2 сигнала Django (pre_save и post_save). Я хотел бы иметь имя пользователя текущего пользователя. Как мне это сделать? Кажется, я не могу отправить запрос, или я этого не понял.Получить текущий входной сигнал пользователя в Django

Благодаря

ответ

10

если вы используете сайт администратора, почему бы не использовать Cutom модель админа

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) 

Сигнал - это то, что срабатывает каждый раз, когда объект сохраняется независимо от того, выполняется ли он администратором или каким-либо процессом, который не привязан к запросу, и на самом деле это не подходящее место делая запросы на основе действий

+0

В феврале 2015 года. Это единственный способ получить запрос пользователя в сигнале Django? –

+0

Это правильный ответ в сочетании с [ModelAdmin.exclude] (https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.exclude) для необходимых предварительно заполненных полей очень полезно. – chirale

+0

Это будет работать для некоторых, но не во всех случаях, например. изменения отношений 'm2m' могут быть связаны только через сигналы. – Ben

1

В обоих сигналов, сигнал послать три аргумента,

  • Комплимент
  • Instance
  • Использование

Что вам нужно, это Мгновенный модифицируется ...

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

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

+0

Правильная идея, но аргументы неправильны. 'sender' (класс, который посылает сигнал) всегда первый. –

+0

Исправлено, спасибо ... То, что вы говорите, является стандартом djanog, но (насколько я его использовал) с использованием параметров params in (instance, sender) также работает (по крайней мере, в моем коде) ... – FallenAngel

+6

uname = instance .username требует, чтобы в вашей модели было поле с именем username? .... Что не мое дело ... – Djanux

1

Вы можете использовать промежуточное программное обеспечение для хранения текущего пользователя: http://djangosnippets.org/snippets/2179/

Тогда вы сможете получить пользователю get_current_user()

+1

Это решение зависит от локаций Thread. Они считаются «плохими» по разным причинам. http://stackoverflow.com/questions/3227180/why-is-using-thread-locals-in-django-bad –

+0

Просто комментарий к тому, что сказал @ AaronC.deBruyn - ссылка, которую он опубликовал, фактически не согласуется с его заявлением, и популярное мнение приходит к выводу о том, что использование локаторов потоков для этой цели ** является приемлемым **. – Ben

0

Мы можем решить эту проблему с помощью классов промежуточного слоя. Создайте класс singleton, в котором будет храниться пользовательская переменная.

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 

Создание собственного промежуточного класса, который будет настройки пользователя, например LoggedInUser и вставить из промежуточного уровня после того, как «» django.contrib.auth.middleware.AuthenticationMiddleware в 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 

В сигналов импорта класс LoggedInUser и получить текущий пользователь

logged_in = LoggedInUser() 
user = logged_in.user 
16

Не желая вмешиваться в нить-локальное состояние, я решил попробовать другой подход. Насколько я могу судить, обработчики сигналов post_save и pre_save называются синхронно в потоке, который вызывает save(). Если мы находимся в нормальном цикле обработки запросов, мы можем просто подойти к стеку, чтобы найти объект запроса как локальную переменную где-нибудь. например

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

Если есть текущий запрос, вы можете получить атрибут user от него.

Примечание: как говорится в inspect модуля документации,

Эта функция опирается на поддержку кадра стека Python в интерпретатор, который не гарантированно существует во всех реализациях Python.

+0

Вы, сэр, легенда. Великолепное решение, работает так же, как рекламируется. – Bosco

+0

Плюсы и минусы этого подхода? –

+2

** Плюсы ** - Работает ли, проще реализовать и избегает локаторов потоков (может или не может быть плохо) ** Минусы ** - Производительность (требуется сканировать стек вызовов потенциально для каждого сигнала) не будет работать через тесты - вам нужно будет добавить дополнительную логику для извлечения объектов запроса из ваших тестов – Ben

Смежные вопросы