Django: kullanıcı oturum açtığında sinyal verir mi?


83

Django uygulamamda, bir kullanıcı oturum açtığında birkaç periyodik arka plan işi çalıştırmaya başlamalı ve kullanıcı oturumu kapattığında bu işleri çalıştırmayı bırakmalıyım, bu yüzden şık bir yol arıyorum

  1. bir kullanıcı oturum açma / oturum kapatma konusunda bilgilendiril
  2. kullanıcı oturum açma durumunu sorgulama

Benim açımdan ideal çözüm şöyle olurdu:

  1. her biri tarafından gönderilen bir sinyal django.contrib.auth.views.loginve... views.logout
  2. django.contrib.auth.models.User.is_logged_in()benzer bir yöntem ... User.is_active()veya... User.is_authenticated()

Django 1.1.1'de buna sahip değil ve kaynağı yamamak ve eklemek konusunda isteksizim (bunu nasıl yapacağımdan emin değilim).

Geçici bir çözüm is_logged_inolarak, UserProfile modeline varsayılan olarak temizlenen, kullanıcının açılış sayfasına ilk kez vurduğunda (tarafından tanımlanan LOGIN_REDIRECT_URL = '/') ayarlanan ve sonraki isteklerde sorgulanan bir boole alanı ekledim . Bunu UserProfile'a ekledim, bu nedenle yerleşik Kullanıcı modelini yalnızca bu amaç için türetmek ve özelleştirmek zorunda kalmıyorum.

Bu çözümü beğenmedim. Kullanıcı açık bir şekilde çıkış düğmesine tıklarsa, bayrağı temizleyebilirim, ancak çoğu zaman kullanıcılar sayfadan ayrılır veya tarayıcıyı kapatır; Bu durumlarda bayrağı temizlemek bana pek kolay gelmiyor. Ayrıca (bu daha çok veri modeli netliği nitpicking olsa da) is_logged_inUserProfile'a değil, User modeline aittir.

Alternatif yaklaşımlar düşünebilen var mı?


4
Lütfen yeni bir cevap seçmeyi düşünün. Şu anda kabul edilen seçenek, 1.3'e eklenen sinyal ışığında çok zayıf bir seçimdir.
Bryson

1
Haklısın; kabul edilen cevabı değiştirdi.
ssc

Yanıtlar:


153

Bunun gibi bir sinyal kullanabilirsiniz (benimkini models.py'ye koyuyorum)

from django.contrib.auth.signals import user_logged_in


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

user_logged_in.connect(do_stuff)

Django belgelerine bakın: https://docs.djangoproject.com/en/dev/ref/contrib/auth/#module-django.contrib.auth.signals ve burada http://docs.djangoproject.com/en/dev/ konular / sinyaller /


8
Artık Django 1.3 bu sinyalleri sunduğuna göre, çağrıyı oturum açmak / oturumu kapatmak için kaydırmaktan çok daha iyi bir çözümdür. Aynı zamanda, yeni oturum açma yöntemleri belirlerseniz - örneğin, Facebook / Twitter / OpenID oturum açma işlemleri - yine de çalışacakları anlamına gelir.
Jordan Reiter

9
Bunun models.pyyerine, kodun içine yerleştirilmesini signals.pyve modüllerin __init__.pydosyasında otomatik olarak içe aktarılmasını öneririm .
Daniel Sokolowski

javascript'i giriş ve çıkışta çalıştırmak için bu sinyali nasıl kullanırım?
Ashish Gupta

16

@PhoebeB cevabına ek olarak: @receiverdekoratörü şu şekilde de kullanabilirsiniz :

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

Ve bunu signals.pyuygulama dizininize koyarsanız, bunu şuraya ekleyin apps.py:

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

13

Bir seçenek, Django'nun oturum açma / oturum kapatma görünümlerini kendi başınıza kaydırmak olabilir. Örneğin:

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)

Daha sonra bu görünümleri Django'nunki yerine kodunuzda kullanırsınız ve işte.

Giriş durumunu sorgulamaya gelince, istek nesnesine erişiminiz varsa oldukça basittir; kayıtlı bir kullanıcı mı yoksa anonim kullanıcı mı olduğunu görmek için isteğin kullanıcı özniteliğini kontrol edin ve tombala. Django belgelerine alıntı yapmak için :

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

İstek nesnesine erişiminiz yoksa, mevcut kullanıcının oturum açıp açmadığını belirlemek zor olacaktır.

Düzenle:

Ne yazık ki, hiçbir zaman User.is_logged_in()işlevsellik elde edemezsiniz - bu, HTTP protokolünün bir sınırlamasıdır. Ancak birkaç varsayımda bulunursanız, istediğiniz şeye yaklaşabilirsiniz.

Birincisi, neden bu işlevi alamıyorsunuz? Birinin tarayıcıyı kapatması ile yeni bir tane getirmeden önce bir sayfada biraz zaman geçirmesi arasındaki farkı anlayamazsınız. Birisi gerçekten siteden çıktığında veya tarayıcıyı kapattığında HTTP üzerinden bunu söylemenin bir yolu yoktur.

Yani burada mükemmel olmayan iki seçeneğiniz var:

  1. unloadBir kullanıcı sayfadan ayrılırken yakalamak için Javascript'in olayını kullanın . Bununla birlikte , sitenizde gezinirken bir kullanıcının oturumunu kapatmadığınızdan emin olmak için dikkatli bir mantık yazmanız gerekir .
  2. Bir kullanıcı oturum açtığında emin olmak için çıkış sinyalini çalıştırın. Ayrıca, süresi dolan oturumları temizlemek için oldukça sık çalışan bir cron işi oluşturun - süresi dolan bir oturum silindiğinde, oturumun kullanıcısının (anonim değilse) artık etkin oturumları olmadığını kontrol edin, bu durumda oturum kapatma sinyalini tetikleyin.

Bu çözümler dağınıktır ve ideal değildir, ancak maalesef yapabileceğiniz en iyi çözümlerdir.


Bu hala "çoğu zaman kullanıcılar sayfadan ayrılır veya tarayıcıyı kapatır" durumuna değinmez.
Joel L

Cevabınız için teşekkürler, tabii ki oturum açma / oturum kapatma beni kaynağa yama yapmaktan kurtarıyor, bunu kendim yapmalıydım. Yine de küçük bir düzeltme: Giriş çağrılmadan önce sinyal my_login'de gönderilirse, kullanıcı hala sinyal işleyicide anonimdir. Daha iyi (bunun doğru şekilde biçimlendirileceğini düşünmeyin): def my_login (istek): response = login (request) #fire a signal veya eşdeğer dönüş yanıtı Ayrıca, is_authenticated'i zaten kullanıyorum, sadece ihtiyacım olacağını hissettim Daha Fazlası. Şimdiye kadar, veri modelindeki yeni is_log_in parçam orada kullanılmamış durumda.
ssc

Her yerde iyi puanlar. Sanırım is_logged_inkonuyu pek iyi ele almadım (orada özür dilerim, sanırım yazıyı okumakta harika bir iş yapmadım), ancak bu alanda elimden gelen yardımı sunmak için cevabı güncelledim . Maalesef bu biraz imkansız bir problem.
ShZ

3

bunun için hızlı bir çözüm, uygulamanızın _ _ init _ _.py alanına aşağıdaki kodu yerleştirin:

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

Tek güvenilir yol (kullanıcının tarayıcıyı ne zaman kapattığını da tespit eder), last_requestkullanıcı bir sayfayı her yüklediğinde bazı alanları güncellemektir .

Ayrıca, kullanıcının bir sayfası açıksa, her x dakikada bir sunucuya ping gönderen periyodik bir AJAX isteğiniz de olabilir.

Ardından, son kullanıcıların bir listesini alan, onlar için işler oluşturan ve bu listede bulunmayan kullanıcılar için işleri temizleyen tek bir arka plan işine sahip olun.


Bu, bir kullanıcının oturum açıp açmadığını ölçmenin en iyi yoludur. Temel olarak, oturum açmış kullanıcıların bir listesini tutmanız ve son erişimlerinin ne olduğunu kontrol etmeniz ve bir zaman aşımına karar vermeniz gerekir. Zaman aşımını 10 dakika gibi bir değere ayarlarsanız ve ardından her web sayfasının bir sayfa etkinken her 5 dakikada bir Ajax isteğini çağırmasını sağlarsanız, bu durum durumu güncel tutmalıdır.
Jordan Reiter

1

Açıkça bir düğmeyi tıklamalarının aksine (hiç kimsenin yapmadığı) oturumu kapatmanın çıkarılması, "oturumu kapattı" anlamına gelen boşta kalma süresi miktarını seçmek anlamına gelir. phpMyAdmin varsayılan olarak 15 dakika kullanır, bazı bankacılık siteleri 5 dakika kadar kısa bir süre kullanır.

Bunu uygulamanın en basit yolu, çerez ömrünü değiştirmektir. Bunu tüm siteniz için belirterek yapabilirsiniz settings.SESSION_COOKIE_AGE. Alternatif olarak, kullanarak bunu kullanıcı bazında (bazı rastgele kriterlere göre) değiştirebilirsiniz HttpResponse.setcookie(). Kendi sürümünüzü oluşturarak render_to_response()ve her yanıtın yaşam süresini ayarlayarak bu kodu merkezileştirebilirsiniz .


0

Kaba fikir - bunun için ara yazılım kullanabilirsiniz. Bu ara yazılım, ilgili URL istendiğinde istekleri işleyebilir ve sinyali tetikleyebilir. Ayrıca, verilen eylem gerçekten başarılı olduğunda yanıtları ve yangın sinyalini işleyebilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.