С результатом запроса мы взаимодействуем через объект cursor
, который можно получить через метод cursor()
объекта соединения.
# получение объекта курсора
cursor = conn.cursor()
Для получения результата после выполнения запроса используются следующие команды:
- cursor.fetchone() — вернуть одну строку
- cursor.fetchall() — вернуть все строки
- cursor.fetchmany(size=10) — вернуть указанное количество строк
curs.execute("SELECT * FROM users;")
all_users = curs.fetchall()
Также курсоры итерируемы, так что получить результаты запросов можно обходом.
curs.execute("SELECT * FROM users;")
for row in curs:
print(row)
Курсоры привязаны к соединению на весь срок жизни, и все команды выполняются в контексте одной сессии базы данных, обернутой соединением. Любые изменения, сделанные в базе данных одним курсором, немедленно видны другим курсорам. Потому хорошей практикой при работе с базой данных является закрытие курсора и соединения с базой. Для автоматизации этого процесса удобно взаимодействовать через контекстный менеджер, используя конструкцию with
:
with conn.cursor() as curs:
curs.execute("SELECT * FROM users;")
all_users = curs.fetchall()
Фабрика
По умолчанию результат возвращается в виде кортежа. Такое поведение возможно изменить, передав параметр cursor_factory
в момент открытия объекта cursor
. Так вместо обычного курсора вернется его подкласс с новыми возможностями.
Наиболее полезные подклассы курсоров:
RealDictCursor
- возвращает данные в виде словаряNamedTupleCursor
- возвращает данные в виде именованного кортежа, более легковесной альтернативы словарюLoggingCursor
- логгирует все запросы в файл или объект логгера
from psycopg2.extras import NamedTupleCursor
with conn.cursor(cursor_factory=NamedTupleCursor) as curs:
curs.execute("SELECT * FROM users WHERE name=%s;", ("Alfred",))
alfred = curs.fetchone()
alfred # (id=10, name='Alfred', age='90')
Серверные курсоры
Когда выполняется запрос к базе данных, курсор получает все записи, возвращаемые базой, бэкендом, передавая их в клиентский процесс. Если запрос возвращает большое количество данных, то и будет выделен пропорционально большой объем памяти на стороне клиента.
Если набор данных слишком велик для практической обработки на стороне клиента, то можно создать курсор на стороне сервера. Используя такой курсор, можно передавать клиенту только контролируемое количество данных, не храня весь объем полностью в памяти.
В Psycopg2 серверные курсоры называются именованными курсорами. Именованный курсор создается с помощью метода cursor()
с указанием параметра name
. Такой курсор ведет себя как обычный курсор, позволяя пользователю перемещаться по набору данных с помощью метода scroll()
и читать данные с помощью методов fetchone()
и fetchmany()
. По умолчанию можно перемещаться только вперед, но если вам нужно перемещаться назад, нужно объявить ваш курсор scrollable
.
with conn.cursor(name="cursor_name", scrollable=True) as curs:
curs.execute("SELECT * FROM users;")
result = curs.fetchall()
Самостоятельная работа
Выполните шаги из урока у себя на компьютере.
Попробуйте использовать NamedTupleCursor
.
Подготовьте запрос, содержащий агрегирующую функцию, например такой:
SELECT MAX(id) from users;
Выполните его и получите результат из именованного кортежа.
Дополнительные материалы
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.