Для одного из сайтов надо было писать начальные социальные штуки, типа количество пользователей онлайн и количество новых комментариев для постов. Т.к. реализация этого с sql базами достаточно затратно по ресурсам и не самое простое дело, то было выбрано nosql хранилище Redis. В нем легко хранить ключи и большое количество значений, которое легко можно получить для конкретных нужд.
Сначала рассмотрим реализацию индикатора пользователей онлайн вместе с Django.
Рассмотрим сначала теоретическую часть работы такого индикатора. Т.к. в вебе нет каких-либо четких механизмов узанавания, кто сейчас на сайте, то применяется простая практика. Каждую минуту записывается, кто из пользователей зашел на сайт, а раз в 5 минут делается выборка (группировка юзеров в каждую минуту) и вычисляется сколько их было. В моем конкретном примере, все пользователи зарегистрированы, т.е. учитывать анонимов не требуется. В Django для учета каждого пользователя и занесения его в базу очень подходит мидлварь (middleware). При заходе пользователя на любую страницу сайта, миддлварь его обрабатывает и заносит в базу со значением ключа указывающем время (например 23:10). А при запросе счетчиком, будут выбираться 5 ключей (23:10, 23:09, 23:08, 23:07, 23:06) объединяться и отдаваться. Общий процесс можно увидеть на картинке (не моей):
Рассмотрим код миддлвари:
class OnlineUsersMiddleware:
def process_request(self, request):
try:
dbwork.set_to_key(request.user.id)
except:
pass
Как видно, вся работа миддлвари это получить id юзера и передать его в функцию работы с базой.
Рассмотрим саму функцию dbwork.set_to_key():
def current_key():
return datetime.now().strftime('%H:%M')
def set_to_key(user_id):
key = current_key()
redis_db.sadd(key, user_id)
redis_db.expire(key, 360)
Первая (current_key) - выдает нам просто время (ее можно и соввместить впринципе), вторая (set_to_key), получает ключ, добавляет в базу ключ set, в который добавляем пользовательский id и устанавливаем на него время жизни 6 минут.
Далее, рассмотри функцию, которая выводит количество пользователей онлайн:
def get_online():
now = datetime.now()
interval = [now - timedelta(minutes=x) for x in range(5)]
interval = [i.strftime('%H:%M') for i in interval]
try:
online = len(redis_db.sunion(interval))
except:
online = 1
return int(online)
тут interval - это список наших ключей, который получается получением дельты с текущим временем и 5 минут назад, потом по нему с помощью sunion() получаем все id пользователей, а len - количество (т.к. мне не нужны были имена, а только количество).
Для получения и выведения этого значения был написан контекст процессор, т.к. значение требуется во всех шаблонах:
def users_online(request):
users = get_online()
return {'count_users_online': users}
Во всех модулях, redis_db это конект к базе редиса через официальный модуль Redis, примерно так открывающий коннект:
try:
redis_db = redis.Redis(host=getattr(settings, 'REDIS_HOST', 'localhost'),
port=getattr(settings, 'REDIS_PORT', 6379),
db=getattr(settings, 'REDIS_DB', 0),
password=getattr(settings, 'REDIS_PASS', ''),
socket_timeout=0.01)
except:
pass
Все, после этого можно использовать. Как видно - делается легко и просто, к тому же не захламляет sql базу и не сказывается на производительности (nosql очень быстр). Вместо использования redis можно использовать тот же memcache.