13

In template, when I use

{% if topic.creator.is_authenticated %}
Online
{% else %}
Offline
{% endif %}

the users turn out to be always online, even when they has signed out a while ago. So I'm wondering how to check the online users correctly?

Vaibhav Mule
  • 5,016
  • 4
  • 35
  • 52
Jand
  • 2,527
  • 12
  • 36
  • 66

6 Answers6

25

‌Thanks this excellent blog post, with slight modifications, I came up with a better solution, which uses memcache, hence less delay per request:

in models.py add:

from django.core.cache import cache 
import datetime
from myproject import settings

and add these method the userprofile class:

def last_seen(self):
    return cache.get('seen_%s' % self.user.username)

def online(self):
    if self.last_seen():
        now = datetime.datetime.now()
        if now > self.last_seen() + datetime.timedelta(
                     seconds=settings.USER_ONLINE_TIMEOUT):
            return False
        else:
            return True
    else:
        return False 

in userprofile folder add this middleware.py

import datetime
from django.core.cache import cache
from django.conf import settings

class ActiveUserMiddleware:

    def process_request(self, request):
        current_user = request.user
        if request.user.is_authenticated():
            now = datetime.datetime.now()
            cache.set('seen_%s' % (current_user.username), now, 
                           settings.USER_LASTSEEN_TIMEOUT)

in settings.py add 'userprofile.middleware.ActiveUserMiddleware', to MIDDLEWARE_CLASSES and also add:

    CACHES = {
        'default': {
            'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
            'LOCATION': '127.0.0.1:11211',              
        }
    }

# Number of seconds of inactivity before a user is marked offline
USER_ONLINE_TIMEOUT = 300

# Number of seconds that we will keep track of inactive users for before 
# their last seen is removed from the cache
USER_LASTSEEN_TIMEOUT = 60 * 60 * 24 * 7

and in profile.html:

 <table>
   <tr><th>Last Seen</th><td>{% if profile.last_seen %}{{ profile.last_seen|timesince }}{% else %}awhile{% endif %} ago</td></tr>
   <tr><th>Online</th><td>{{ profile.online }}</td></tr>
 </table>

That's it!

To test cache in the console, to make sure that memcache works fine:

$memcached -vv
$ python manage.py shell
>>> from django.core.cache import cache
>>> cache.set("foo", "bar")
>>> cache.get("foo")
'bar'
>>> cache.set("foo", "zaq")
>>> cache.get("foo")
'zaq'
Community
  • 1
  • 1
Jand
  • 2,527
  • 12
  • 36
  • 66
  • 1
    changed for new version add these : from django.utils.deprecation import MiddlewareMixin class ActiveUserMiddleware(MiddlewareMixin): .....and request.user.is_authenticated: instead of request.user.is_authenticated(): – BUGATTI AJAY Jun 17 '20 at 20:04
  • hi @Jand :) I hope you're well! Could you just have a look to my question please? https://stackoverflow.com/questions/63668786/django-user-online-offline-user-none-false-even-if-user-is-online – Louis Aug 31 '20 at 14:56
8

As the documentation says:

Even though normally you will check is_autheticated attribute on request.user to find out whether it has been populated by the AuthenticationMiddleware (representing the currently logged-in user), you should know this attribute is True for any User instance.

So to check if user is online I would do something like this:

models.py

class Profile(models.Model):
    user = models.OneToOneField(User, related_name='profile')           
    is_online = models.BooleanField(default=False)

views.py

from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver    

@receiver(user_logged_in)
def got_online(sender, user, request, **kwargs):    
    user.profile.is_online = True
    user.profile.save()

@receiver(user_logged_out)
def got_offline(sender, user, request, **kwargs):   
    user.profile.is_online = False
    user.profile.save()

And then in your template you would check if user is online:

{% if user.profile.is_online %}
    Online
{% else %}
    Offline
{% endif %}

Don't forget to return user instance to your template in order for user.profile.is_online to work.

Ahtisham
  • 9,170
  • 4
  • 43
  • 57
2

You can have an integer field for each user saying the number of sessions the user has logged in currently. You can increase that by 1 every time the user logs in somewhere, and reduce it by 1 when the user logs out somewhere.

{% if topic.creator.login_count %}
Online
{% else %}
Offline
{% endif %}

This is a simple way to solve this problem. You can refresh this data through an ajax request periodically.

Aswin Murugesh
  • 10,831
  • 10
  • 40
  • 69
  • Would you please elaborate on how to refresh the page through ajax requests? – Jand Apr 16 '15 at 15:39
  • @Randi: You can have a url where you send the username as parameter and get the data as to know if the user is logged in or not. And then, refresh the data on that particluar div – Aswin Murugesh Apr 16 '15 at 18:38
  • How scaleable this solution will be? – Jand Apr 16 '15 at 19:02
  • @Randi I cannot comment on that until I know more about what your implementation is and how many users you will have to check – Aswin Murugesh Apr 17 '15 at 01:28
2

first install django-online-users by running

pip install django-online-users

then in your settings.py

INSTALLED_APPS = [
...
'online_users',] 
MIDDLEWARE_CLASSES = (
...
'online_users.middleware.OnlineNowMiddleware',)

Then in your views

import online_users.models



def see_users(self):

  user_status = online_users.models.OnlineUserActivity.get_user_activities(timedelta(seconds=60))
  users = (user for user in  user_status)
  context = {"online_users"}`

Pass the context to your template for example

{% for user in users %}
  {{user.user}}
{% endfor %}

This will output the users who have been active and online for the last 60 seconds

MMTimothy
  • 21
  • 3
1

The reason a user appears to always be online is described in the Django documentation:

is_authenticated()

  • Always returns True ... This is a way to tell if the user has been authenticated. This does not imply any permissions, and doesn’t check if the user is active or has a valid session.

There are a number of ways you could achieve this, but none are "build-in".

This question covers the last activity time of a user, and you could use that to check if a user was active in the past few minutes.

Alternatively, you can query the Session table to check if the user has an active session, but this may be inaccurate if you have long session timeouts.

Community
  • 1
  • 1
1

Yes it does. But the correct way to check if a user is logged in or not is to use : request.user.is_authenticated. This will return True if the person is logged in other wise False.

eg:

in the template:

{% if request.user.is_authenticated ==True %}
      do something awesome.

in views pass request into the template.

return render('url/filename.html',{'any variable name':request})
Debojit Kaushik
  • 103
  • 1
  • 1
  • 6
  • No - is_authenticated returns True for all valid users on the regardless of whether that are logged in : https://docs.djangoproject.com/en/2.0/ref/contrib/auth/#django.contrib.auth.models.User - this is true all the way back to 1.7 at least. Also - the User object is passed into the Template automatically - so long as you have the default middleware enabled. : https://docs.djangoproject.com/en/2.0/topics/auth/default/#authentication-data-in-templates Again True back to 1.7 as far as I can see – Tony Suffolk 66 Apr 07 '18 at 07:03