L
7 февраля 2021 г. 0:50

Не работает код на статус онлайн

Django

При попытке добавить код для статуса как встатье, я сталкнулся с проблемой, что он не записывает данные в бд(поля last_online NULL), такое ощущение, что бек просто не работает. Можете подсказать как это исправить?
Версия Django 3.1.6
Версия питона 3.8.2
Модель юзера

  1. from django.db import models
  2. from django.contrib.auth.models import User
  3. from PIL import Image
  4. from django.urls import reverse
  5. from django.contrib.humanize.templatetags.humanize import naturaltime
  6. from django.utils import timezone
  7.  
  8.  
  9. class Profile(models.Model):
  10. user = models.OneToOneField(User, on_delete=models.CASCADE)
  11. image = models.ImageField(default='default.jpg', upload_to='profile_pics')
  12. last_online = models.DateTimeField(blank=True, null=True)
  13.  
  14. def __str__(self):
  15. return f'{self.user.username} Profile'
  16.  
  17. # В данном методе проверяем, что дата последнего посещения не старше 15 минут
  18. def is_online(self):
  19. if self.last_online:
  20. return (timezone.now() - self.last_online) < timezone.timedelta(minutes=15)
  21. return False
  22.  
  23. def get_online_info(self):
  24. if self.is_online():
  25. return 'Онлайн'
  26. if self.last_online:
  27. return f'Последнее посещение: {naturaltime(self.last_online)}'
  28. else:
  29. return 'Не известно'

код MyBackend

  1. from django.contrib.auth import get_user_model
  2. from django.utils import timezone
  3. from django.contrib.auth.backends import BaseBackend
  4.  
  5.  
  6. class MyBackend(BaseBackend):
  7.  
  8. def get_user(self, user_id):
  9. try:
  10. user = get_user_model().objects.get(pk=user_id)
  11. user.last_online = timezone.now() # При запросе пользователя выполним обновлении
  12. # даты и времени последнего посещения
  13. user.save(update_fields=['last_online'])
  14. return user
  15. except get_user_model().DoesNotExist:
  16. return None

файл settings

  1. AUTHENTICATION_BACKENDS = (
  2. 'users.backends.MyBackend',
  3. 'django.contrib.auth.backends.ModelBackend',
  4. )

код темплейта

  1. <span class="caption-1">Статус</span>
  2. <span class="body-2">{{ user.get_online_info }}</span>
2
Вопрос задан по статьеDjango - Урок 048. Как добавить статус онлайн на сайте

Вам это нравится? Поделитесь в социальных сетях!

6
Илья Чичак
  • 7 февраля 2021 г. 2:09

auth_backend - это про другое. Попробуйте сделать это через middleware?

    L
    • 7 февраля 2021 г. 2:14

    пишет такое

    1. TypeError: MyBackend() takes no arguments
    1. MIDDLEWARE = [
    2. 'django.middleware.security.SecurityMiddleware',
    3. 'django.contrib.sessions.middleware.SessionMiddleware',
    4. 'django.middleware.common.CommonMiddleware',
    5. 'django.middleware.csrf.CsrfViewMiddleware',
    6. 'django.contrib.auth.middleware.AuthenticationMiddleware',
    7. 'django.contrib.messages.middleware.MessageMiddleware',
    8. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
    9. 'users.backends.MyBackend',
    10. 'django.contrib.auth.middleware.AuthenticationMiddleware',
    11. 'blacklist.middleware.blacklist_middleware',
    12. ]
      Илья Чичак
      • 7 февраля 2021 г. 2:30

      так, я поторопился. Надо разбираться
      если вы делаете через auth_backend - last_online будет проставляться только в момент логина. Если сделать через middleware, оно будет обновляться каждый раз,когда пользователь будет делать что-либо.
      Тоесть, в первом случае, пользователь может авторизоваться и пользоваться сайтом час-два,но спустя 15 минут будет показано, что он оффлайн. А если нет протухания сессии, пользователь может и на следующий день вернуться, а показано будет, что он оффлайн.
      Во втором случае, пока он ходил по ссылкам и выполняет запросы - он будет отображаться, как онлайн. Но возрастет нагрузка на базу.

      если нагрузка по боку, я бы сделал такую middleware:

      1. class LastOnlineMiddleware:
      2. def __init__(self, get_response):
      3. self.get_response = get_response
      4.  
      5. def __call__(self, request):
      6. if request.user.is_authenticated:
      7. get_user_model().filter(id=request.user.id).update(last_online=timezone.now())
      8. response = self.get_response(request)
      9. return response

      так одним запросом будет обновляться его поле а дальше запросы будут выполняться, как выполнялись

        L
        • 7 февраля 2021 г. 2:49

        На нагрузку без разницы, и для меня ваш вариант подходит, но к сожалению выбивает в ошибку.

        1. Internal Server Error: /
        2. Traceback (most recent call last):
        3. File "C:\Python38\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
        4. response = get_response(request)
        5. File "C:\Users\Livis\PycharmProjects\djangosite\users\backends.py", line 25, in __call__
        6. get_user_model().filter(id=request.user.id).update(last_online=timezone.now())
        7. AttributeError: type object 'User' has no attribute 'filter'

        Я заменил класс MyBackend, на ваш предложенный

        1. class LastOnlineMiddleware:
        2. def __init__(self, get_response):
        3. self.get_response = get_response
        4.  
        5. def __call__(self, request):
        6. if request.user.is_authenticated:
        7. get_user_model().filter(id=request.user.id).update(last_online=timezone.now())
        8. response = self.get_response(request)
        9. return response
        1. MIDDLEWARE = [
        2. 'django.middleware.security.SecurityMiddleware',
        3. 'django.contrib.sessions.middleware.SessionMiddleware',
        4. 'django.middleware.common.CommonMiddleware',
        5. 'django.middleware.csrf.CsrfViewMiddleware',
        6. 'django.contrib.auth.middleware.AuthenticationMiddleware',
        7. 'django.contrib.messages.middleware.MessageMiddleware',
        8. 'django.middleware.clickjacking.XFrameOptionsMiddleware',
        9. 'users.backends.LastOnlineMiddleware',
        10. 'django.contrib.auth.middleware.AuthenticationMiddleware',
        11. 'blacklist.middleware.blacklist_middleware',
        12. ]
          Илья Чичак
          • 7 февраля 2021 г. 3:51
          • Ответ был помечен как решение.

          опечатался:
          get_user_model().filter(id=request.user.id).update(last_online=timezone.now())
          поменять на:
          get_user_model().objects.filter(id=request.user.id).update(last_online=timezone.now())

            L
            • 7 февраля 2021 г. 6:17

            Спасибо за уделенное время, всё работает

              Комментарии

              Только авторизованные пользователи могут публиковать комментарии.
              Пожалуйста, авторизуйтесь или зарегистрируйтесь