Peewee ORM манипуляция базами данных

Ни для кого не новость, что большинство сегодняшних приложений взаимодействуют с базами данных. Особенно с движками на основе RDBMS (движки DB с поддержкой SQL). Как и любой другой язык программирования, Pyhton также предоставляет как собственные библиотеки для взаимодействия с базами данных, так и от третьих лиц. Как правило, вам нужно прописать запросы SQL для CRUD операций. Это нормально, однако иногда получается мешанина:

  • Шеф решил перейти с MySQL в… MSSQL и у вас нет выбора, кроме как кивнуть и внести правки в свои запросы в соответствии с другим движком баз данных;
  • Вам нужно сделать несколько запросов, чтобы получить одну часть данных из другой таблицы;
  • Список можно продолжать долго, не так ли?

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Чтобы разобраться с этим, в игру вступает ORM.

Введение в ORM

ORM – это акроним от Object Relational Mapping (Объектно-реляционное отображение). Но что именно оно делает?

Из википедии:

Объектно-реляционное отображение — это технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных». Существуют как проприетарные, так и свободные реализации этой технологии.
Звучит круто, да?

Что такое Peewee?

Peewee (http://docs.peewee-orm.com/en/latest/) – это небольшое ORM, которое в данный момент поддерживает postgresql, mysql и sqlite. Разумеется, это не единственное ORM для разработчиков Python. К примеру, Django предоставляет собственную ORM библиотеку, кроме этого, всегда есть SqlAlchemy. Хорошая сторона Peewee – это то, что он занимает мало места, его легко освоить, и вы можете приступить к работе с приложениями за несколько минут.

Достаточно слов, перейдем к кодам!

Установка Peewee

Как и многие другие библиотеки Python, вы можете установить Peewee при помощи pip:

Настройка базы данных

Как я говорил, Peewee поддерживает ряд движков для работы с базами данных (полный список тут: http://docs.peewee-orm.com/en/latest/peewee/database.html), в данной статье я использую MySQL.

Объект MySQLDatabase создан.

Создание моделей в Peewee

Сейчас я перейду к созданию моделей. В этой статье я использую две таблицы или модели: «Категория» и «Продукт«. Категория может содержать несколько продуктов. Сохраняем как файл models.py

Сначала я создал BaseModel. Это связанно с тем, что Peewee просит вас передать dbhandle в каждый класс Model. Чтобы избежать лишних движений, я просто создал базовый класс и расширил его. Ознакомиться со всеми типами столбцов в таблице можно тут: http://docs.peewee-orm.com/en/latest/peewee/models.html#field-types-table

Хорошо, наша BaseModel и Category созданы. Модель Category состоит из четырех полей:

  1. id, который является полем автоматического прироста;
  2. name содержит имя категории;
  3. updated_at и created_at – поля timestamp, которые определяют настоящее время по умолчанию.

В классе Meta я передаю название таблицы в собственность db_table. Это не обязательно, если название таблицы и модели одинаковые. Собственность order_by указывает, какой столбец должен использоваться для сортировки данных во время извлечения. Вы можете переписать его, передав вид по полю на ваше усмотрение.

Перед тем как мы двинемся дальше, я хочу создать еще один файл под названием operations.py, в котором я буду использовать эти модели.

После импорта, я подключаюсь к базе данных. Ошибка peewee.OperationalError ссылается на все ошибки, связанные с Peewee. К примеру, если вы введете неправильные учетные данные, вы получите следующее:

Затем мы вызываем Category.create_table(), которые создает таблицу с указанной ранее собственностью. Если вы передаете safe=True в качестве параметра, то существующая таблица просто перепишется. Это может привести к проблемам в реальной ситуации.

Далее, модель Product:

Она аналогична модели Cateogory. Разница только в ForeignKeyField, который указывает, как именно Product должен быть связан с Category. Обновление основы должно выглядеть следующим образом:

После запуска указанного выше кода, создается таблица модели product, а также отношение с таблицей categories. Вот скриншот моего клиента sql:

Peewee ORM манипуляция базами данных

Вставка записи (INSERT)

Теперь мы можем перейти к добавлению данных сперва в category, а затем в таблицу products. Так как у нас есть рабочие модели, не так просто добавлять или обновлять записи.

Я добавил функцию под названием add_category() с параметром и именем внутри. Объект Category создан, как и поля таблицы, которые являются переданной собственностью данного объекта класса. В нашем случае, это поле name.

The row.save() сохраняет данные из объекта в базу данных.

Круто, не так ли? Больше не нужно прописывать уродливые INSERT-ы.

Теперь добавим product.

add_product берет name, price и category_id в качестве вводных данных. Сначала, я проверю, существует ли категория, если да – значит её объекты хранятся в базе. В ORM вы имеете дело с объектом, по этому вы передаете информацию о категории в качестве объекта, так как мы уже определили эту взаимосвязь ранее.

Далее, я буду создавать разделы в main.py:

Теперь добавим продукты:

Полный main.py можете видеть ниже:

Я передаю имя категории, как только её объект будет найден и передан объекту класса Product. Если вы хотите пойти по пути SQL, для начала вам нужно выполнить SELECT, чтобы получить существующий category_id, и затем назначить id добавляемому продукту.

Так как работать с ORM – значит иметь дело с объектами, мы храним объекты вместо скалярных значений. Кто-то может посчитать это слишком «инженерным» методом в нашем случае, но подумайте о случаях, когда вы понятия не имеете о том, какая база данных должна быть использована в будущем. Ваш код – это универсальный инструмент для работы с базами данных, так что если он работает с MySQL, или MSSQL, то он будет работать даже с MongoDb (гипотетически).

Выбор нескольких записей

Сначала выделяем категории:

Category.select() возвращает ВСЮ запись, которая будет отсортирована по столбцу created_at, что мы и указали в классе Meta.

Теперь выбираем все продукты:

Здесь я перебираю продукты и добавляю запись в список product_data. Обратите внимание на доступ к категории продукта. Больше нет SELECT для получения ID, с последующим поиском названия. Простой цикл делает все за нас. При запуске, информация о продукте будет отображаться следующим образом:

Выбор одной записи

Чтобы выбрать одну запись, вам нужно использовать метод get:

Теперь это называется так:

Название товара передано функции find_product, если запись существует – она вернет экземпляр Product. Здесь я вывожу категорию, связанную с этим продуктом.

Обновление записей в Peewee

Обновление записей – это так же просто, как и их создание. Вы получаете экземпляр объекта, после чего обновляете его.

После этого, вызываем его как:

Удаление записей в Peewee

Удаление записи не сильно отличается от обновления:

Вызываем данную функцию для удаления раздела:

Обратите внимание на то, что после удаления записи, вы также удаляете связанные продукты, так как они подключены к категории, и мы уже определили сценарий во время удаления раздела ON_DELETE, будут удаляться и товары из раздела.

Готовое приложение
Сохраняем данные криптовалют от биржи Binance

Допустим у нас уже есть MySQL база данных и существует таблица: coins. Нам нужно создать модель для этой существующей таблице и сохранить полученные json данные от Binance.

Структура базы данных:

Данные от Binance мы получим по ссылке: https://api.binance.com/api/v1/ticker/24hr для HTTP запроса мы будет использовать библиотеку Requests на примере.

Что мы реализуем в нашем приложении:

  • Добавление новых монет;
  • Проверка если монета существует;
  • Обновления данных по цене если монета существует;
  • Сортируем монеты по объему за 24 часа;
  • Кол-во монет которые торгуются с BNB в паре (Binance Coin);
  • Выбираем случайные 5 монет

Исходный код

В третьей строке вы можете видеть список типов столбцов из таблицы, такие как Integer, Float и Varchar (IntegerField, FloatField, CharField, PrimaryKeyField, TimestampField). Подробнее про тип полей можете узнать из документации: https://peewee.readthedocs.io/en/2.0.2/peewee/fields.html

Больше примеров которые не были использованы: http://docs.peewee-orm.com/en/latest/peewee/querying.html

Результат который я получил:

Peewee ORM манипуляция базами данных

Меняем MySQL на SQLite

Используя пример из кода выше, мы изменим базу данных из MySQL на SQLite не трогая код (кроме самого подключения). Нам нужно обновить немного наш файл. С самых первых строк было:

Теперь у нас:

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

Ошибка в примере «Выбираем случайные 5 монет», в коде мы используем fn.Rand() и он работает для MySQL, но для SQLite и PostgreSQL он работать не будет, нужно использовать fn.Random(). Подробнее: http://docs.peewee-orm.com/en/latest/peewee/querying.html#getting-random-records

После запуска у нас появился файл базы данных binance-coins.db

Peewee ORM манипуляция базами данных

Вывод

Отлично, вы освоили основы Peewee и то, как вы можете использовать эту маленькую и эффективную ORM в ваших следующих проектах, связанных с Pyhton. Если у вас есть дополнительные вопросы – вы можете ознакомиться с официальной документацией и найти в ней ответы.