Django:ユーザーがログインしたときに通知しますか?


83

私の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ブールフィールドをUserProfileモデルに追加しました。これはデフォルトでクリアされ、ユーザーが最初にランディングページ(で定義LOGIN_REDIRECT_URL = '/')にアクセスしたときに設定され、後続のリクエストでクエリされます。これをUserProfileに追加したので、その目的のためだけに組み込みのUserモデルから派生してカスタマイズする必要はありません。

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

誰かが別のアプローチを考えることができますか?


4
新しい答えを選択することを検討してください。1.3で追加された信号を考慮すると、現在受け入れられているものは非常に貧弱な選択です。
ブライソン2011

1
あなたが正しい; 受け入れられた答えを変更しました。
ssc 2013年

回答:


153

あなたはこのような信号を使うことができます(私は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ドキュメントを参照してください:https//docs.djangoproject.com/en/dev/ref/contrib/auth/#module-django.contrib.auth.signalsおよびここhttp://docs.djangoproject.com/en/dev/トピック/シグナル/


8
Django 1.3がこれらのシグナルを提供するようになったので、ログイン/ログアウトの呼び出しをラップするよりもはるかに優れたソリューションです。また、新しいログイン方法(Facebook / Twitter / OpenIDログインなど)を設定しても、引き続き機能することを意味します。
ジョーダンライター2011

9
代わりにそれを入れるのではmodels.pyなく、コードを入れsignals.pyてモジュールの__init__.pyファイルに自動インポートすることをお勧めします。
Daniel Sokolowski 2013年

このシグナルを使用して、ログインおよびログアウト時にjavascriptを実行する方法は?
Ashish Gupta 2015年

16

@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アプリのディレクトリに配置する場合は、これをapps.py次の場所に追加します。

class AppNameConfig(AppConfig):
    ...
    def ready(self):
        import app_name.signals

13

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のドキュメントを引用するには:

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イベントを使用して、ユーザーがページを離れるタイミングをキャッチします。ただし、ユーザーがまだサイトをナビゲートしているときにユーザーがログアウトしないように、注意深いロジックを作成する必要があります
  2. 念のため、ユーザーがログインするたびにログアウト信号を発します。また、期限切れのセッションをフラッシュするためにかなり頻繁に実行されるcronジョブを作成します。期限切れのセッションが削除されたら、セッションのユーザー(匿名でない場合)にアクティブなセッションがないことを確認します。アクティブなセッションがなくなった場合は、ログアウト信号を送信します。

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


これは、「ほとんどの場合、ユーザーはページを離れるか、ブラウザを閉じるだけです」という状況にはまだ対処していません。
Joel L

あなたの答えに感謝します、もちろん、ログイン/ログアウトをラップすることは私がソースにパッチを当てるのを防ぎます、それは私自身であるはずです。ただし、少し修正します。ログインが呼び出される前にシグナルがmy_loginで送信された場合、ユーザーはシグナルハンドラーで匿名のままです。より良い(これが適切にフォーマットされるとは思わない):def my_login(request):response = login(request)#fire a signal、or equal return responseまた、私はすでにis_authenticatedを使用しているので、必要だと感じました。それ以上。ただし、これまでのところ、データモデルの新しいis_logged_in部分は未使用のままです。
ssc 2010年

すべての周りの良い点。私は実際にはあまりうまく対処していなかったと思いますis_logged_in(そこで謝罪しました、私は投稿を読むのに素晴らしい仕事をしなかったと思います)が、私はその分野で私ができることを提供するために答えを更新しました。残念ながら、これは少し不可能な問題です。
shZ 2010年

3

これに対する簡単な解決策は、アプリの_ _ 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....')

1

信頼できる唯一の方法(ユーザーがブラウザーを閉じたことも検出する)はlast_request、ユーザーがページをロードするたびにフィールドを更新することです。

また、ユーザーがページを開いている場合にx分ごとにサーバーにpingを実行する定期的なAJAXリクエストを作成することもできます。

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


これは、ユーザーがログインしているかどうかを測定するための最良の方法です。基本的に、ログインしたユーザーの名簿を保持し、最後のアクセスが何であったかを確認して、タイムアウトを決定する必要があります。タイムアウトを10分程度に設定し、ページがアクティブな間、各Webページで5分ごとにAjaxリクエストを呼び出すようにすると、ステータスが最新の状態に保たれます。
ジョーダンライター2011

1

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

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


0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.