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

автор

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

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

Чтобы разобраться с этим, в игру вступает 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:

Вставка записи (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

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

  • Добавление новых монет;
  • Проверка если монета существует;
  • Обновления данных по цене если монета существует;
  • Сортируем монеты по объему за 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

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

Меняем 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 в ваших следующих проектах, связанных с Pyhton. Если у вас есть дополнительные вопросы – вы можете ознакомиться с официальной документацией и найти в ней ответы.

Вам может быть интересно

Scroll Up