Зарегистрируйтесь, чтобы продолжить обучение

Запросы Python: SQL

Как правило, запросы в базу формируются динамически на основе данных, которые поступают из вне. Например, создание пользователя чаще всего происходит во время регистрации. В таком случае код вставки выглядит так:

name = "Tota"
phone = "1234"

sql = f"INSERT INTO users (username, phone) VALUES ('{name}', '{phone}');"
cursor.execute(sql)
conn.commit()

Запросы составленные таким образом несут в себе серьезную опасность называемую SQL-инъекцией. Вместо обычных данных, пользователь может отправить текст, изменяющий SQL-запрос на тот, который нужен пользователю. Представьте что внутри переменной бы хранилась строка ') INSERT INTO users (username, phone) VALUES ('i am hacker', '777777'). В таком случае, после подстановки мы бы получили следующий запрос:

INSERT INTO users (username, phone) VALUES ('somename', '');
INSERT INTO users (username, phone) VALUES ('i am hacker', '777777');

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

В разработке существует правило - никогда не доверяй пользовательским данным. В случае работы с базой данных, это особенно важно. Любые данные перед вставкой должны быть экранированы. Делается это с помощью специальных плейсхолдеров:

name = "John"
age = 19

with conn.cursor() as curs:
    # для позиционных аргументов всегда передается последовательность, даже если параметр один
    # здесь передается кортеж (name,)
    curs.execute("SELECT id, name FROM users WHERE name=%s;", (name,))
    curs.fetchall()

with conn.cursor() as curs:
    # также можно использовать именованные аргументы
    curs.execute(
        "INSERT INTO users (name, age) VALUES (%(name)s, %(age)s);",
        {"age": age, "name": name},
    )
    conn.commit()

conn.close()

Позиционные плейсхолдеры %s, которые расставляются в тех местах, где ожидается подстановка данных. Также плейсхолдеры могут быть и именованными %(имя)s.

Напоследок несколько полезных советов по построению запросов:

  • Плейсхолдер должен быть %s даже если тип подставляемого значения отличается от строки
  • Не заключайте плейсходер в кавычки
  • Если в запросе используется знак %, он должен быть указан как %%

Ускорение запросов

Psycopg2 предоставляет дополнительные функции execute_batch() и execute_values() для исполнения множества запросов за один раз.

from psycopg2.extras import execute_batch, execute_values

users = (
    ("Bob", "bob@mail.com"),
    ("Alice", "alice@mail.com"),
    ("John", "john@mail.com"),
)
execute_batch(curs, "INSERT INTO users (name, email) VALUES (%s, %s)", users)

# в случае execute_values запрос будет выглядеть так
users = [
    ("Bob", "bob@mail.com"),
    ("Alice", "alice@mail.com"),
    ("John", "john@mail.com"),
]
execute_values(curs, "INSERT INTO users (name, email) VALUES %s", users)

Возврат идентификатора

Когда мы вставляем данные в базу, иногда нам нужно получить идентификатор вставленной записи и потом использовать его в коде. Например, когда мы создаем какую-то сущность и хотим потом ее использовать:

user = User()
# Сохраняем пользователя в базу данных
# После этого становится доступен id
id = user.get_id()
# Его можно использовать для формирования ссылок или вставки связанных записей

К сожалению, Psycopg2 не предоставляет встроенного инструмента для получения id записей, но для этого мы можем использовать синтаксис SQL:

# RETURNING возвращает указанное поле
 with conn.cursor() as cur:
        cur.execute(
            "INSERT INTO users (name, email) VALUES (%s, %s) RETURNING id;",
            (user.name, user.email)
        )
        user.id = cur.fetchone()[0]
conn.close()

Самостоятельная работа

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

Добавьте в базу данных несколько пользователей, используя плейсхолдеры

Используя плейсхолдеры, удалите одного из созданных пользователей по его имени


Дополнительные материалы

  1. Передача параметров

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff