web-dev-qa-db-ja.com

post_saveシグナルでユーザーのリクエストにアクセスする

プロジェクトで以下の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を取得して保存します。どのようにそれを行うことができますか?

38
Mo J. Mughrabi

できません。現在のユーザーは、リクエストを介してのみ利用できます。純粋なモデル機能を使用している場合は利用できません。どういうわけかビューでユーザーにアクセスします。

スタックを調べてビューを探し、ビューのローカル変数を調べてリクエストを取得することで、それを行うことができました。それは少しハックのように感じますが、うまくいきました。

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
PaulR

イグナシオは正しいです。 Djangoのモデル信号は、インスタンスに関連付けられたイベントとそれらの尊重されるデータについて他のシステムコンポーネントに通知することを目的としているため、たとえば、モデルからのリクエストデータにアクセスできないことは有効だと思いますpost_saveシグナル。ただし、リクエストデータがインスタンスに保存されているか、インスタンスに関連付けられている場合を除きます。

それを処理する方法はたくさんありますが、悪いものから良いものまでさまざまですが、これはprimeがこれを自動的に処理するクラスベース/関数ベースの汎用ビューを作成するための例だと思いますあなたのために。

CreateViewUpdateView、またはDeleteViewから継承するビューに、監査が必要なモデルで動作する動詞を処理する場合、AuditMixinクラスから追加で継承させる。 AuditMixinは、オブジェクトを正常に作成、更新、削除するビューにフックして、データベースにエントリを作成できます。

完全な意味があり、非常にきれいで、簡単に差し込むことができ、幸せなポニーを生み出します。フリップサイド?間もなくリリースされるDjango 1.3リリースを使用するか、関数ベースの汎用ビューをいじくり回してそれぞれに新しいビューを提供する必要があります。監査操作。

7

トレーサビリティのために、モデルに2つの属性を追加します(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()

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

この目的で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#revision-api

5
bjorn

次のようなミドルウェアを追加してみませんか。

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
4
firebird631

あなたがこれを理解したと想像しますが、同じ問題があり、作成するすべてのインスタンスが、それらを作成するユーザーへの参照を持っていることに気付きました(あなたが探しているものです)

1
kiril
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',
)