web-dev-qa-db-ja.com

Django:ユーザーがログインしたときにシグナルを送信しますか?

私のDjangoアプリでは、ユーザーがログインするといくつかの定期的なバックグラウンドジョブの実行を開始し、ユーザーがログアウトすると実行を停止する必要があるため、エレガントな方法を探しています

  1. ユーザーのログイン/ログアウトの通知を受け取る
  2. ユーザーのログイン状態のクエリ

私の観点から、理想的なソリューションは

  1. 各_Django.contrib.auth.views.login_および_... views.logout_によって送信されるシグナル
  2. Django.contrib.auth.models.User.is_logged_in()または... User.is_active()に類似したメソッド... User.is_authenticated()

Django 1.1.1にはそれがなく、ソースにパッチを適用して追加することに消極的です(とにかくそれを行う方法がわかりません)。

一時的な解決策として、ユーザープロファイルモデルに_is_logged_in_ブールフィールドを追加しました。これはデフォルトでクリアされ、ユーザーがランディングページに初めてアクセスしたときに設定され(_LOGIN_REDIRECT_URL = '/'_で定義)、クエリされますその後のリクエスト。それをUserProfileに追加したので、その目的のためだけに組み込みのUserモデルから派生してカスタマイズする必要はありません。

私はこの解決策が好きではありません。ユーザーが明示的にログアウトボタンをクリックすると、フラグをクリアできますが、ほとんどの場合、ユーザーはページを離れるか、ブラウザーを閉じます。これらの場合にフラグをクリアすることは、私には簡単ではありません。 (ただし、それはむしろデータモデルの明快さの選択です)、_is_logged_in_はUserProfileではなく、Userモデルに属します。

誰もが代替アプローチを考えることができますか?

72
ssc

このような信号を使用できます(models.pyに私のものを入れます)

from Django.contrib.auth.signals import user_logged_in


def do_stuff(sender, user, request, **kwargs):
    whatever...

user_logged_in.connect(do_stuff)

Django docs: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#module-Django.contrib.auth.signals を参照してくださいそしてここ http://docs.djangoproject.com/en/dev/topics/signals/

138
PhoebeB

1つのオプションは、Djangoのログイン/ログアウトビューを独自のものでラップすることです。例えば:

_from Django.contrib.auth.views import login, logout

def my_login(request, *args, **kwargs):
    response = login(request, *args, **kwargs)
    #fire a signal, or equivalent
    return response

def my_logout(request, *args, **kwargs):
    #fire a signal, or equivalent
    return logout(request, *args, **kwargs)
_

次に、Djangoのビューではなく、これらのビューをコードで使用します。

ログインステータスのクエリに関しては、リクエストオブジェクトにアクセスできれば非常に簡単です。リクエストのユーザー属性をチェックして、それらが登録ユーザーか匿名ユーザーか、ビンゴかを確認します。 Django documentation を引用するには:

_if request.user.is_authenticated():
    # Do something for logged-in users.
else:
    # Do something for anonymous users.
_

要求オブジェクトにアクセスできない場合、現在のユーザーがログインしているかどうかを判断するのは困難です。

編集:

残念ながら、User.is_logged_in()機能を取得することはできません-これはHTTPプロトコルの制限です。ただし、いくつかの仮定を行うと、望むものに近づくことができる場合があります。

まず、なぜその機能を利用できないのですか?さて、あなたは誰かがブラウザを閉じているのか、誰かが新しいものを取得する前にページでしばらく過ごしているのかを区別することはできません。誰かが実際にサイトを離れたときやブラウザを閉じたときにHTTPで通知する方法はありません。

したがって、完璧ではない2つのオプションがあります。

  1. Javascriptのunloadイベントを使用して、ユーザーがページを離れたときにキャッチします。ただし、ユーザーがyourサイトをナビゲートしているときにユーザーをログアウトさせないように、慎重なロジックを記述する必要があります。
  2. 念のため、ユーザーがログインするたびにログアウト信号を発します。また、かなり頻繁に実行して期限切れのセッションをフラッシュするcronジョブを作成します。期限切れのセッションが削除されたら、セッションのユーザー(匿名でない場合)にアクティブなセッションがないことを確認します。この場合、ログアウト信号を発します。

これらのソリューションは面倒で理想的ではありませんが、残念ながらあなたができる最善の方法です。

13
ShZ

@PhoebeBの答えに加えて、次のように@receiverデコレーターを使用することもできます。

from Django.contrib.auth.signals import user_logged_in
from Django.dispatch import receiver

@receiver(user_logged_in)
def post_login(sender, user, request, **kwargs):
    ...do your stuff..`

そして、アプリのディレクトリのsignals.pyに配置した場合、これをapp.pyに追加します。

def ready(self):
    import app_name.signals`
8
bershika

明示的にボタンをクリックするのではなく(誰もクリックしない)、ログアウトを推測するということは、「ログアウト」に相当するアイドル時間を選択することを意味します。 phpMyAdminはデフォルトの15分を使用しますが、一部の銀行サイトではわずか5分しか使用しません。

これを実装する最も簡単な方法は、cookie-lifetimeを変更することです。 _settings.SESSION_COOKIE_AGE_ を指定することで、サイト全体でこれを行うことができます。または、 HttpResponse.setcookie() を使用して、ユーザーごとに(任意の基準セットに基づいて)変更できます。独自のバージョンの render_to_response() を作成し、各応答の有効期間を設定することにより、このコードを集中化できます。

1
Peter Rowell

唯一の信頼できる方法(ユーザーがブラウザを閉じたことを検出する方法)は、いくつかのlast_requestフィールドは、ユーザーがページを読み込むたびに表示されます。

また、ユーザーがページを開いている場合に、x分ごとにサーバーにpingを送信する定期的なAJAX要求を出すこともできます。

次に、最近のユーザーのリストを取得する単一のバックグラウンドジョブを作成し、それらのジョブを作成し、そのリストに存在しないユーザーのジョブをクリアします。

1
Joel L

大まかなアイデア-これにはミドルウェアを使用できます。このミドルウェアは、リクエストを処理し、関連するURLがリクエストされるとシグナルを発することができます。また、指定されたアクションが実際に成功したときに、応答と発火信号を処理することもできます。

0

これに対する簡単な解決策は、アプリの_ _ init _ _.pyに次のコードを配置することです。

from Django.contrib.auth.signals import user_logged_in
from Django.dispatch import receiver


@receiver(user_logged_in)
def on_login(sender, user, request, **kwargs):
    print('User just logged in....')
0
Rui Lima