Гид по технологиям

Регистрация пользователей в Python и SQLite: пошаговое руководство

6 min read Разработка Обновлено 26 Apr 2026
Регистрация в Python с SQLite
Регистрация в Python с SQLite

Кратко: это руководство показывает, как создать простую систему регистрации пользователей на Python с использованием SQLite. Разбираем соединение, курсоры, методы выполнения запросов, проверку уникальности email, безопасное хранение паролей и практики для продакшена.

Логотип Python слева и изображение базы данных в виде цилиндра справа.

Python содержит встроенную поддержку баз данных, поэтому для простых приложений можно обойтись стандартной библиотекой и SQLite без фреймворков вроде Django ORM. SQLite легковесен, не требует отдельного сервера и отлично подходит для прототипов, десктоп-приложений и мелких сервисов.

В этом материале вы найдёте не только базовые примеры создания базы и таблиц, но и советы по безопасности, отладке, тестам и возможным миграциям в продакшн.

Что нужно знать в начале

Определения в одну строку:

  • Соединение: объект, который открывает файл базы данных и управляет транзакциями.
  • Курсор: объект для исполнения SQL-запросов и извлечения результатов.
  • Транзакция: группа операций, которые выполняются атомарно и фиксируются с помощью commit или отменяются rollback.

Основная идея: открываем соединение, создаём курсор, выполняем запросы, фиксируем изменения и закрываем ресурсы.

Как создать соединение и курсор

Простейший код создания базы выглядит так:

import sqlite3

# Подключиться к (новой) базе
conn = sqlite3.connect('path/to/database.db')

# Создать курсор
cursor = conn.cursor()

# Закрыть курсор и соединение
cursor.close()
conn.close()

Если файла по указанному пути нет, SQLite создаст его. Обратите внимание: в реальной программе лучше использовать контекстный менеджер чтобы автоматически закрывать соединение и гарантировать commit/rollback.

Пример с контекстным менеджером:

import sqlite3

with sqlite3.connect('database.db') as conn:
    cursor = conn.cursor()
    # операции с курсором
    cursor.close()
# при выходе из with вызывается conn.commit() если не было исключения

Важно: поведение commit в with зависит от версии Python и sqlite3. Обычно при нормальном завершении менеджера выполняется commit, при исключении происходит rollback.

Три способа выполнить SQL в sqlite3

  1. Cursor.execute

Выполняет одиночный SQL-запрос. Подходит для создания таблиц, одиночных вставок, селектов.

cursor.execute('''
CREATE TABLE IF NOT EXISTS users (
    first_name TEXT,
    last_name TEXT,
    email TEXT UNIQUE,
    password TEXT
)
''')
  1. Cursor.executemany

Выполняет один и тот же запрос для набора параметров. Хорошо подходит для пакетной вставки.

data = [
    ('Alice', 25),
    ('Bob', 30),
    ('Charlie', 22),
]

cursor.executemany('INSERT INTO people (name, age) VALUES (?, ?)', data)
  1. Cursor.executescript

Выполняет скрипт SQL, содержащий несколько выражений подряд. Удобно для миграций из файла.

with open('path/to/script.sql') as f:
    sql_script = f.read()

cursor.executescript(sql_script)

Если вы используете executescript и в скрипте есть COMMIT, то дополнительные вызовы conn.commit не нужны.

Пример: регистрация пользователей — шаг за шагом

Ниже реализована простая регистрация с валидацией пароля, проверкой уникальности email и безопасным хранением пароля с использованием PBKDF2 (встроенная библиотека hashlib). Код ориентирован на консольное приложение, но идеи применимы и к веб-приложениям.

Шаг 1. Подключение и создание таблицы

import sqlite3
import hashlib
import os
import binascii

DB_PATH = 'database.db'

def get_connection():
    return sqlite3.connect(DB_PATH)

# Создать таблицу пользователей
with get_connection() as conn:
    cur = conn.cursor()
    cur.execute('''
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        first_name TEXT,
        last_name TEXT,
        email TEXT UNIQUE,
        password_hash TEXT,
        salt TEXT
    )
    ''')
    cur.close()

К столбцу password теперь сохраняются password_hash и salt. Это безопаснее, чем хранить пароль в открытом виде.

Шаг 2. Функции для хеширования пароля

Используем PBKDF2 с sha256, который доступен в hashlib и считается безопасным при корректной настройке параметров.

import hashlib
import os
import binascii

def hash_password(password: str, salt: bytes = None) -> tuple:
    if salt is None:
        salt = os.urandom(16)
    pwd_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt, 100_000)
    return binascii.hexlify(pwd_hash).decode('ascii'), binascii.hexlify(salt).decode('ascii')

def verify_password(stored_hash: str, stored_salt: str, provided_password: str) -> bool:
    salt = binascii.unhexlify(stored_salt.encode('ascii'))
    pwd_hash, _ = hash_password(provided_password, salt)
    return pwd_hash == stored_hash

Пояснение: 100_000 итераций — распространённое безопасное значение, но его можно увеличить с учётом требований производительности.

Шаг 3. Сбор и валидация данных от пользователя

Пример функции регистрации с проверкой пароля и обработкой ошибки целостности при дублирующемся email.

import sqlite3

def register_user():
    first_name = input('Введите имя: ')
    last_name = input('Введите фамилию: ')

    while True:
        email = input('Введите email: ')
        password1 = input('Введите пароль: ')
        password2 = input('Подтвердите пароль: ')

        if password1 != password2:
            print('Пароли не совпадают. Попробуйте ещё раз.')
            continue

        # Простейшая проверка формата email
        if '@' not in email or '.' not in email.split('@')[-1]:
            print('Некорректный формат email. Попробуйте ещё раз.')
            continue

        password_hash, salt = hash_password(password1)

        try:
            with get_connection() as conn:
                cur = conn.cursor()
                cur.execute('INSERT INTO users (first_name, last_name, email, password_hash, salt) VALUES (?, ?, ?, ?, ?)',
                            (first_name, last_name, email, password_hash, salt))
                cur.close()
            print('Вы успешно зарегистрированы.')
            break
        except sqlite3.IntegrityError:
            print('Ошибка: email уже зарегистрирован. Введите другой email.')

В этом коде мы используем параметризованные запросы с плейсхолдером ? — это защищает от SQL-инъекций и является рекомендуемой практикой.

Шаг 4. Логин пользователя

def login_user():
    email = input('Введите email: ')
    password = input('Введите пароль: ')

    with get_connection() as conn:
        cur = conn.cursor()
        cur.execute('SELECT id, password_hash, salt FROM users WHERE email = ?', (email,))
        row = cur.fetchone()
        cur.close()

    if row is None:
        print('Пользователь не найден.')
        return False

    user_id, stored_hash, stored_salt = row
    if verify_password(stored_hash, stored_salt, password):
        print('Вход успешен. id:', user_id)
        return True
    else:
        print('Неверный пароль.')
        return False

Практические советы и улучшения

  • Никогда не храните пароли в открытом виде. Всегда используйте устойчивый алгоритм хеширования с солью.
  • Всегда используйте параметризованные запросы вместо форматирования строк для предотвращения SQL-инъекций.
  • Для многопользовательских веб-приложений рассмотрите использование серверной СУБД (PostgreSQL, MySQL) вместо SQLite. SQLite лишён сетевой многопоточности и имеет ограничения по конкурентности записи.
  • Для сложных схем и миграций применяйте инструменты миграций (Alembic, Django Migrations, Flyway и т.п.)
  • Логи и мониторинг: логируйте ошибки доступа и исключения, но не логируйте содержимое паролей или полных токенов.

Отладка: частые ошибки и как их решать

  • sqlite3.IntegrityError при дублировании email: обрабатывать и возвращать понятное сообщение пользователю.
  • OperationalError: database is locked: возникает при попытке записи из нескольких потоков/процессов одновременно. Решения: уменьшить время транзакций, использовать пул соединений или перейти на серверную СУБД.
  • Отсутствие commit: если вы не видите изменений в файле базы — убедитесь, что вызван conn.commit() или используете with.

Когда стоит перейти с SQLite на серверную СУБД

Примеры признаков, когда SQLite уже не подходит:

  • Вы ожидаете высокую частоту одновременных записей.
  • Нужны сложные роли/разграничение доступа на уровне БД.
  • Планируется масштабирование с множеством реплик.

В таких случаях рассмотрите PostgreSQL как зрелый выбор для продакшена.

Тесты и критерии приёмки

Критерии приёмки простого модуля регистрации:

  • Успешная регистрация создаёт запись с хешем и солью.
  • Повторная регистрация с тем же email возвращает ошибку IntegrityError и не создаёт запись.
  • Валидация пароля: при совпадении пользователь регистрируется; при несовпадении — нет.
  • При логине верный пароль приводит к успешному входу, неверный — нет.

Минимальные тесты (unit tests):

  • Тест создания таблицы.
  • Тест hash_password и verify_password.
  • Тест вставки и обработки IntegrityError.
  • Тест сценария регистрации + логина.

Чеклист ролей

Разработчик:

  • Использовать параметризованные запросы;
  • Обеспечить хеширование паролей;
  • Добавить базовую валидацию email и политики паролей.

Опережение/DevOps:

  • Настроить бэкапы файла SQLite;
  • Оценить необходимость перехода на серверную СУБД;
  • Настроить ротацию логов и мониторинг ошибок.

Безопасность:

  • Не хранить секреты в репозитории;
  • Проводить аудит доступа к файлу базы;
  • Рассмотреть двухфакторную аутентификацию для продакшена.

Миграция и совместимость

Если вы планируете миграцию с SQLite на PostgreSQL или MySQL:

  • Экспортируйте данные в SQL или CSV;
  • Проверьте различия в типах данных и ограничениях;
  • Перепроверьте индексирование и уникальные ограничения;
  • Используйте инструмент миграций, чтобы управлять версионированием схемы.

Альтернативы и когда они лучше

  • Django ORM: если вы уже используете Django или хотите упростить работу с моделями и миграциями.
  • SQLAlchemy: мощная ORM для гибкости и переносимости между СУБД.
  • TinyDB / Shelve: для очень простых локальных данных без SQL.

Примеры ошибок и откат транзакций

Пример использования транзакции с явным rollback:

import sqlite3

conn = sqlite3.connect('database.db')
cur = conn.cursor()
try:
    cur.execute('BEGIN')
    cur.execute('INSERT INTO users (first_name) VALUES (?)', ('Test',))
    # имитируем ошибку
    raise Exception('something went wrong')
    conn.commit()
except Exception:
    conn.rollback()
finally:
    cur.close()
    conn.close()

Инструменты для просмотра и отладки

  • DB Browser for SQLite: удобный графический интерфейс для просмотра файлов SQLite.

Окно DB Browser for SQLite c одной записью пользователя в таблице.

Краткий методологический план разработки модуля регистрации

  1. Спроектировать таблицу users с полями id, first_name, last_name, email, password_hash, salt.
  2. Реализовать функцию hash_password и verify_password.
  3. Реализовать register_user с валидацией и обработкой IntegrityError.
  4. Реализовать login_user и покрыть юнит-тестами.
  5. Провести ревью безопасности и настроить бэкапы.

Короткий словарь терминов

  • SQLite: файловая реляционная СУБД.
  • Cursor: объект для выполнения SQL в Python.
  • PBKDF2: алгоритм устойчивого хеширования паролей с солью.

Important: для продакшена минимальный набор дополнений включает безопасное хеширование паролей, защиту от утечек логов с секретами и стратегию бэкапов.

Ниже — краткое резюме и рекомендации.

Резюме

  • Для простых приложений SQLite и стандартного модуля sqlite3 Python дают быстрый путь к работе с базой данных.
  • Всегда используйте параметризованные запросы и хешируйте пароли.
  • При росте нагрузки переходите на серверную БД и используйте миграции.

Примените предложенные практики: контекстные менеджеры для соединений, PBKDF2 для паролей, и простые тесты для приёмки. Это обеспечит безопасную и отлаживаемую систему регистрации.

Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Быстрые настройки Nintendo Switch: как открыть и использовать
Гайды

Быстрые настройки Nintendo Switch: как открыть и использовать

Встроить субтитры в видео с Avidemux
Видео

Встроить субтитры в видео с Avidemux

Как перестать бояться камеры и начать снимать
Создание контента

Как перестать бояться камеры и начать снимать

Точки восстановления в Windows 11 — включение и создание
Windows

Точки восстановления в Windows 11 — включение и создание

Микропривычки: маленькие шаги к большим результатам
Саморазвитие

Микропривычки: маленькие шаги к большим результатам

Какая MOBA вам подходит
Игры

Какая MOBA вам подходит