Доступ к запросу пользователя в сигнале post_save - PullRequest
31 голосов
/ 17 января 2011

Я сделал ниже сигнал 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, я хочу получить user_id и сохранить его. Есть идеи, как это сделать?

Ответы [ 9 ]

21 голосов
/ 17 января 2011

Не может быть сделано.Текущий пользователь доступен только через запрос, который недоступен при использовании только функциональных возможностей модели.Доступ к пользователю в представлении как-то.

10 голосов
/ 31 августа 2015

Я смог это сделать, проверив стек и выполнив поиск представления, а затем просмотрев локальные переменные для получения запроса.Это похоже на взлом, но это сработало.

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
7 голосов
/ 18 января 2011

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

Я думаю, что есть много способов справиться с этим, начиная от худшего к лучшему, но я бы сказал, что это простой пример для создания на основе классов /обобщенные представления на основе функций, которые будут автоматически обрабатывать это для вас.

Ваши представления, которые наследуются от CreateView, UpdateView или DeleteView, дополнительно наследуют от вашего класса AuditMixin, если они обрабатывают глаголы, которые работаютна моделях, которые должны быть проверены.AuditMixin может затем подключаться к представлениям, которые успешно создают \ обновляют \ удаляют объекты и создают запись в базе данных.

Создает совершенный смысл, очень чистый, легко подключаемый и рождает счастливых пони.Оборотная сторона?Либо вам нужно будет выпустить релиз Django 1.3, который скоро выйдет, либо вам придется потратить некоторое время, изменяя основные функциональные представления на основе функций и предоставляя новые для каждой операции аудита.

5 голосов
/ 28 августа 2017

Вы также можете использовать 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())

Подробнее об их API https://django -reversion.readthedocs.io / en / stable / api.html #пересмотр-апи

5 голосов
/ 02 февраля 2016

Для отслеживаемости добавьте два атрибута к вашей модели (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)

views.py

    p = Question.objects.get(pk=1)
    p.question_text = 'some new text'
    p.updated_by = request.user
    p.save()

сигналов.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))
4 голосов
/ 23 июня 2016

Почему бы не добавить промежуточное ПО с чем-то вроде этого:

class RequestMiddleware(object):

    thread_local = threading.local()

    def process_request(self, request):
        RequestMiddleware.thread_local.current_user = request.user

и более поздними в вашем коде (особенно в сигнале в этой теме):

thread_local = RequestMiddleware.thread_local
if hasattr(thread_local, 'current_user'):
    user = thread_local.current_user
else:
    user = None
0 голосов
/ 11 января 2019

Вы можете сделать небольшой взлом, переопределив метод модели save() и установив пользователя для сохраненного экземпляра в качестве дополнительного параметра.Чтобы получить пользователя, я использовал get_current_authenticated_user() из django_currentuser.middleware.ThreadLocalUserMiddleware (см. https://pypi.org/project/django-currentuser/).

В вашем 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)

В вашем signals.py:

@receiver(post_save, sender=YourModel)
def your_model_saved(sender, instance, **kwargs):
    user = getattr(instance, 'current_authenticated_user', None)

PS: не забудьте добавить 'django_currentuser.middleware.ThreadLocalUserMiddleware' к вашему MIDDLEWARE_CLASSES.

0 голосов
/ 18 ноября 2014
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',
)
0 голосов
/ 25 марта 2014

Я думаю, вы бы поняли это, но у меня была та же проблема, и я понял, что все создаваемые мной экземпляры имели ссылку на пользователя, который создает их (что вы и искали) )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...