#13 Сессии во Flask

Сессии — еще один способ хранить данные конкретных пользователей между запросами. Они работают по похожему на куки принципу. Для использования сессии нужно сперва настроить секретный ключ. Объект session из пакета flask используется для настройки и получения данных сессии. Объект session работает как словарь, но он также может отслеживать изменения.

При использовании сессий данные хранятся в браузере как куки. Куки, используемые для хранения данных сессии — это куки сессии. Тем не менее в отличие от обычных куки Flask криптографически отмечает куки сессии. Это значит, что каждый может видеть содержимое куки, но не может их менять, не имея секретного ключа для подписи. Как только куки сессии настроены, каждый последующий запрос к серверу подтверждает подлинность куки с помощью такого же секретного ключа. Если Flask не удается это сделать, тогда его контент отклоняется, а браузер получает новые куки сессии.

Знакомые с сессиями из языка PHP заметят, что сессии во Flask немного отличаются. В PHP куки сессии не хранят данные о сессии, а только id сессии. Это уникальная строка, которую PHP создает для ассоциации данных сессии с куки. Данные сессии хранятся на сервере в виде файла. При получении запроса от пользователя PHP использует id сессии, чтобы найти данные сессии и отобразить их в коде. Такой тип сессий известен как серверный, а те, которые используются во Flask, называется клиентскими.

По умолчанию различий между куки и клиентскими сессиями во Flask не так много. В итоге клиентские сессии страдают от тех же недостатков, что и обычные куки:

  • Не могут хранить конфиденциальную информацию, такую как пароли.
  • Дают лишнюю нагрузку при каждом запросе.
  • Не способны хранить больше 4 КБ.
  • Ограничены в общем количестве куки для одного сайта

и так далее.

Единственное реальное различие между куки и клиентскими сессиями — Flask гарантирует, что содержимое куки сессии не может быть изменено пользователям (только если у него нет секретного ключа).

Для использования клиентских сессий во Flask можно или написать собственный интерфейс сессии или использовать расширения, такие как Flask-Session или Flask-KVSession.

Как читать, записывать и удалять данные сессии

Следующий код демонстрирует, как можно читать, записывать и удалять данные сессии. Откроем файл main2.py, чтобы добавить следующий код после функции представления article():

from flask import  Flask, render_template, request, redirect, url_for, flash, make_response, session
#...
@app.route('/visits-counter/')
def visits():
    if 'visits' in session:
	session['visits'] = session.get('visits') + 1  # чтение и обновление данных сессии
    else:
	session['visits'] = 1  # настройка данных сессии
    return "Total visits: {}".format(session.get('visits'))

@app.route('/delete-visits/')
def delete_visits():
    session.pop('visits', None)  # удаление данных о посещениях
    return 'Visits deleted'
#...

Стоит обратить внимание, что объект session используется как обычный словарь. Если сервер не запущен, нужно его запустить и зайти на https://localhost:5000/visits-counter/. На странице будет счетчик посещений:

Сессии во Flask 1

Чтобы увеличить его, нужно несколько раз обновить страницу.

Сессии во Flask 12

Flask отправляет куки сессии клиенту только при создании новой сессии или изменении существующей. При первом посещении https://localhost:5000/visits-counter/ будет исполнено тело else в функции представления visits(), в результате чего будет создана новая сессия. При создании новой сессии Flask отправит куки сессии клиенту. Последующие запросы к https://localhost:5000/visits-counter приведут к исполнению кода в блоке if, в котором обновляется значение счетчика visits сессии. При изменении сессии будет создан новый файл куки, поэтому Flask отправит новые куки сессии клиенту.

Чтобы удалить данные сессии нужно зайти на https://localhost:5000/delete-visits/.

Удаление данных сессии

Если сейчас открыть https://localhost:5000/visits-counter, счетчик посещений снова будет показывать 1.

Сессии во Flask 1

По умолчанию куки сессии существуют до тех пор, пока не закроется браузер. Чтобы продлить жизнь куки сессии, нужно установить значение True для атрибута permanent объекта session. Когда значение permanent равно True, срок куки сессии будет равен permanent_session_lifetime. permanent_session_lifetime — это атрибут datetime.timedelta объекта Flask. Его значение по умолчанию равно 31 дню. Изменить его можно, выбрав новое значение для атрибута permanent_session_lifetime, используя ключ настройки PERMANENT_SESSION_LIFETIME.

import datetime

app = Flask(__name__)
app.permanent_session_lifetime = datetime.timedelta(days=365)
# app.config['PERMANENT_SESSION_LIFETIME'] = datetime.timedelta(days=365)

Как и request, объект sessions доступен в шаблонах.

Изменение данных сессии

Примечание: перед тем как следовать инструкции, нужно удалить куки, установленные локальным хостом.

Большую часть времени объект session автоматически подхватывает изменения. Но бывают случаи, например изменение структуры изменяемых данных, которые не подхватываются автоматически. Для таких ситуаций нужно установить значение True для атрибута modified объекта session. Если этого не сделать, Flask не будет отправлять обновленные куки клиенту. Следующий код показывает, как использовать атрибут modified объекта session. Откроем файл main2.py, чтобы добавить следующий код перед функцией представления delete_visitis().

#...
@app.route('/session/')
def updating_session():
    res = str(session.items())

    cart_item = {'pineapples': '10', 'apples': '20', 'mangoes': '30'}
    if 'cart_item' in session:
	session['cart_item']['pineapples'] = '100'
	session.modified = True
    else:
	session['cart_item'] = cart_item

    return res
#...

При первом посещении https://localhost:5000/session/ код в блоке else будет исполнен. Он создаст новую сессию, где данные сессии будут в виде словаря. Последующий запрос к https://localhost:5000/session/ обновляет данные сессии, установив количество «ананасов» на значении 100. В следующей строке атрибут modified получает значение True, потому что без него Flask не будет отправлять обновленные куки сессии клиенту.

Если сервер не запущен, его следует запустить и зайти на https://localhost:5000/session/. Отобразится пустой словарь session, потому что у браузера еще нет куки сессии, которые он мог бы отправить серверу:

Все данные сессии во Flask 1

Если страницу перезагрузить, в словаре session будет уже «10 ананасов»:

Все данные сессии во Flask 2

Перезагрузив страницу в третий раз, можно увидеть, что словарь session имеет значение «ананасов» равное 100, а не 10:

Все данные сессии во Flask 2

Объект сессии подхватил изменение благодаря атрибуту modified. Удостовериться в этом можно, удалив куки сессии и закомментировав строку, где для атрибута modified устанавливается значение True. Теперь после первого запроса значение словаря сессии будет равно «10 ананасам».

Это все, что нужно знать о сессиях во Flask. И важно не забывать, что по умолчанию сессии во Flask являются клиентскими.