Django: get last user visit date

前端 未结 7 2202
隐瞒了意图╮
隐瞒了意图╮ 2020-12-13 04:28

In Django, we can get the time user last logged in by using Auth.User.last_login. That is only updated when the user logs in using his username/password. Supp

相关标签:
7条回答
  • 2020-12-13 05:00

    This is my lastvisitmiddleware.py file which I have added in the settings.py file as a middleware

    from django.utils.timezone import now
    from myapp.models import UserLastVisit
    from django.contrib.auth.models import User
    
    class LastVisitMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            if request.user.is_authenticated:
                # Update last visit time after request finished processing.
                user = User.objects.get(id=request.user.id)
                userLastVisit = UserLastVisit.objects.filter(user_id=user)
                if userLastVisit:
                    userLastVisit.update(last_visit=now())
                else:
                    UserLastVisit.objects.create(user_id=user, last_visit=now())
    
            response = self.get_response(request)
            return response
    

    setings.py file

    MIDDLEWARE = [
       ...
       'mysite.lastvisitmiddleware.LastVisitMiddleware',
       ...
    ]
    

    models.py

    class UserLastVisit(models.Model):
        user_id = models.ForeignKey(User, models.DO_NOTHING, db_column='user_id')
        last_visit = models.DateTimeField()
    

    This solution worked for me. Now, every time a user visits the site, the UserLastVisit table will be updated with the latest last_visit. One problem in that is if user travel between different pages, then also the last visit will be updated. We can use a time range like 24 hrs or something like that to update it only once in that time range. It combines multiple approaches from the answers available on this thread

    0 讨论(0)
  • 2020-12-13 05:06

    The same as John Lehmann's middleware, but rewritten as a function with Andrew Swihart's suggestions and tested on Django 2.2:

     def last_user_activity_middleware(get_response):
    
        def middleware(request):
    
            response = get_response(request)
    
            key = "last-activity"
    
            if request.user.is_authenticated:
    
                last_activity = request.session.get(key)
    
                # If key is old enough, update database.
                too_old_time = timezone.now() - td(seconds=60 * 60)
                if not last_activity or parse(last_activity) < too_old_time:
                    MyUser.objects.filter(email=request.user).update(
                        last_visit=timezone.now(),
                        login_count=F('login_count') + 1)
    
                request.session[key] = timezone.now().isoformat()
    
            return response
    
        return middleware
    

    Learn more about writing own middleware in official documentation: https://docs.djangoproject.com/en/2.2/topics/http/middleware/#writing-your-own-middleware

    0 讨论(0)
  • 2020-12-13 05:12

    Taking into account @John Lehmann solution and @Andrew Swihart suggestions, I came up with this code for newer versions of Django (> 2.0):

    from datetime import timedelta as td
    from django.utils import timezone
    from django.conf import settings
    from django.db.models.expressions import F
    from dateutil.parser import parse
    
    from .models import Account
    
    
    class AccountLoginMiddleware:
    
        def __init__(self, get_response):
            self.get_response = get_response
    
        def __call__(self, request):
            if request.user.is_authenticated:
                last_activity = request.session.get('last-activity')
    
                too_old_time = timezone.now() - td(seconds=settings.LOGIN_INTERVAL)
                if not last_activity or parse(last_activity) < too_old_time:
                    Account.objects.filter(username=request.user.username).update(
                        login_last=timezone.now(),
                        login_count=F('login_count') + 1)
    
                request.session['last-activity'] = timezone.now().isoformat()
    
            response = self.get_response(request)
    
            return response
    
    0 讨论(0)
  • 2020-12-13 05:15

    Here's a middleware that will keep track of user last activity and count separated by intervals of time. Using the interval creates discrete "sessions" which can be tracked/counted along with the benefit of minimizing writes to the database.

    Every time an auth user performs a request, will hit the cache to find their last activity, and then update the cache with a new timestamp. If the activity has had a gap of at least "interval" time, then it will update the database timestamp.

    from datetime import timedelta as td
    from django.utils import timezone
    from django.conf import settings
    from django.db.models.expressions import F    
    from <user profile path> import UserProfile  
    
    class LastUserActivityMiddleware(object):
        KEY = "last-activity"
    
        def process_request(self, request):
            if request.user.is_authenticated():
                last_activity = request.session.get(self.KEY)
    
                # If key is old enough, update database.
                too_old_time = timezone.now() - td(seconds=settings.LAST_ACTIVITY_INTERVAL_SECS)
                if not last_activity or last_activity < too_old_time:
                    UserProfile.objects.filter(user=request.user.pk).update(
                            last_login=timezone.now(),
                            login_count=F('login_count') + 1)
    
                request.session[self.KEY] = timezone.now()
    
            return None
    

    Comments:

    1. How you define settings.LAST_ACTIVITY_INTERVAL_SECS determine what constitutes the interval of non-activity considered to be a new login.
    2. This updates a "UserProfile" object which I have 1:1 with my User objects, but you can update any object you please.
    3. Make sure to include this in settings.MIDDLEWARE_CLASSES.
    4. Note this middleware uses process_request not process_response otherwise depending on middleware order, APPEND_SLASH may cause request.user to be unavailable as discussed: Django: WSGIRequest' object has no attribute 'user' on some pages?
    0 讨论(0)
  • 2020-12-13 05:16

    Example model:

    class User(models.Model):
        last_visit = models.DateTimeField(...)
        ...
    

    Example middleware which will be executed for all logged-in users:

    from django.utils.timezone import now
    
    class SetLastVisitMiddleware(object):
        def process_response(self, request, response):
            if request.user.is_authenticated():
                # Update last visit time after request finished processing.
                User.objects.filter(pk=request.user.pk).update(last_visit=now())
            return response
    

    Add the new middleware to Your settings.py:

    MIDDLEWARE_CLASSES = (
        ...
        'path.to.your.SetLastVisitMiddleware',
        ...
    )
    

    Warning: not tested, but doesn't require external packages to be installed and it's only 5 lines of code.

    See more in the docs about Middleware and custom user models (since Django 1.5)

    0 讨论(0)
  • 2020-12-13 05:16

    The solution of @John Lehmann is wonderful. However, it requires using specific cache-based sessions settings to avoid database write on each request.

    There are two options in cache-based sessions, backends.cache or backends.cached_db. The second one is a write-through cache, i.e. each modification to session data is written on both the database as well as cache. This provides persistency across restarts.

    I have re-written the above to explicitly use the cache function and avoid many database writes.

    from django.core.cache import cache
    from django.utils import timezone
    # other user model import
    
    def last_visit_middleware(get_response):
    
        def middleware(request):
            """
            Save the time of last user visit
            """
            response = get_response(request)
    
            if request.session.session_key:
                key = "recently-seen-{}".format(request.session.session_key)
                recently_seen = cache.get(key)
    
                # is_authenticated hits db as it selects user row
                # so we will hit it only if user is not recently seen
                if not recently_seen and request.user.is_authenticated:
                    UserAccount.objects.filter(id=request.user.id) \
                        .update(last_visit=timezone.now())
    
                    visit_time = 60 * 30    # 30 minutes
                    cache.set(key, 1, visit_time)
    
            return response
    
        return middleware
    

    The records the time of last arrival or last visit. It does not record the time of last exit or "last seen".

    0 讨论(0)
提交回复
热议问题